普通视图

发现新文章,点击刷新页面。
今天 — 2026年1月1日首页

C# 上位机开发中的动态绑定与虚拟化

作者 七宝三叔
2026年1月1日 16:16

一、动态绑定 (Dynamic Binding)

1. 数据绑定基础

csharp

// Model类
public class DeviceData : INotifyPropertyChanged
{
    private string _deviceName;
    private double _temperature;
    private DateTime _timestamp;
    
    public string DeviceName
    {
        get => _deviceName;
        set
        {
            _deviceName = value;
            OnPropertyChanged();
        }
    }
    
    public double Temperature
    {
        get => _temperature;
        set
        {
            _temperature = value;
            OnPropertyChanged();
            OnPropertyChanged(nameof(TemperatureFormatted));
        }
    }
    
    public DateTime Timestamp
    {
        get => _timestamp;
        set
        {
            _timestamp = value;
            OnPropertyChanged();
        }
    }
    
    // 计算属性
    public string TemperatureFormatted => $"{_temperature:F1}°C";
    
    // INotifyPropertyChanged 实现
    public event PropertyChangedEventHandler PropertyChanged;
    
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. 动态绑定集合

csharp

// ViewModel
public class DeviceViewModel : INotifyPropertyChanged
{
    private ObservableCollection<DeviceData> _devices;
    private DeviceData _selectedDevice;
    
    public ObservableCollection<DeviceData> Devices
    {
        get => _devices;
        set
        {
            _devices = value;
            OnPropertyChanged();
        }
    }
    
    public DeviceData SelectedDevice
    {
        get => _selectedDevice;
        set
        {
            _selectedDevice = value;
            OnPropertyChanged();
        }
    }
    
    // 动态添加设备
    public void AddDevice(string name)
    {
        var device = new DeviceData
        {
            DeviceName = name,
            Temperature = 25.0,
            Timestamp = DateTime.Now
        };
        
        Devices.Add(device);
    }
    
    // 动态更新数据
    public void UpdateDeviceTemperature(string deviceName, double temperature)
    {
        var device = Devices.FirstOrDefault(d => d.DeviceName == deviceName);
        if (device != null)
        {
            device.Temperature = temperature;
            device.Timestamp = DateTime.Now;
        }
    }
}

3. XAML绑定示例

xml

<!-- MainWindow.xaml -->
<Window x:Class="MonitorApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
    <Grid>
        <!-- DataGrid动态绑定 -->
        <DataGrid ItemsSource="{Binding Devices}"
                  SelectedItem="{Binding SelectedDevice}"
                  AutoGenerateColumns="False"
                  VirtualizingPanel.IsVirtualizing="True">
            <DataGrid.Columns>
                <DataGridTextColumn Header="设备名称" 
                                    Binding="{Binding DeviceName}"/>
                <DataGridTextColumn Header="温度" 
                                    Binding="{Binding TemperatureFormatted}"/>
                <DataGridTextColumn Header="更新时间" 
                                    Binding="{Binding Timestamp, StringFormat=HH:mm:ss}"/>
            </DataGrid.Columns>
        </DataGrid>
        
        <!-- 实时数据显示 -->
        <ItemsControl ItemsSource="{Binding Devices}"
                      VirtualizingPanel.IsVirtualizing="True">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border Margin="5" Padding="10" Background="LightGray">
                        <StackPanel>
                            <TextBlock Text="{Binding DeviceName}" 
                                       FontWeight="Bold"/>
                            <TextBlock Text="{Binding TemperatureFormatted}" 
                                       Foreground="Red"/>
                        </StackPanel>
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </Grid>
</Window>

二、虚拟化 (Virtualization)

1. UI虚拟化实现

csharp

// 自定义虚拟化数据源
public class VirtualizedDataSource<T> : IList, INotifyCollectionChanged
{
    private readonly List<T> _data;
    private readonly int _pageSize;
    private Dictionary<int, T> _cache;
    
    public VirtualizedDataSource(IEnumerable<T> data, int pageSize = 100)
    {
        _data = data.ToList();
        _pageSize = pageSize;
        _cache = new Dictionary<int, T>();
    }
    
    // 虚拟化访问
    public object this[int index]
    {
        get
        {
            if (!_cache.ContainsKey(index))
            {
                // 加载数据页
                LoadPage(index / _pageSize);
            }
            return _cache[index];
        }
        set => throw new NotImplementedException();
    }
    
    private void LoadPage(int pageNumber)
    {
        int start = pageNumber * _pageSize;
        int end = Math.Min(start + _pageSize, _data.Count);
        
        for (int i = start; i < end; i++)
        {
            _cache[i] = _data[i];
        }
    }
    
    public int Count => _data.Count;
    
    // 实现其他必要接口...
}

// 使用示例
public class LargeDataViewModel
{
    public VirtualizedDataSource<DeviceData> VirtualizedDevices { get; }
    
    public LargeDataViewModel()
    {
        // 生成大量数据
        var data = Enumerable.Range(1, 100000)
            .Select(i => new DeviceData
            {
                DeviceName = $"设备_{i}",
                Temperature = 20 + i % 30,
                Timestamp = DateTime.Now.AddSeconds(-i)
            });
        
        VirtualizedDevices = new VirtualizedDataSource<DeviceData>(data);
    }
}

2. 高级虚拟化配置

xml

<!-- 虚拟化ListView -->
<ListView ItemsSource="{Binding VirtualizedDevices}"
          VirtualizingPanel.IsVirtualizing="True"
          VirtualizingPanel.VirtualizationMode="Recycling"
          VirtualizingPanel.ScrollUnit="Pixel"
          VirtualizingPanel.CacheLength="100,100"
          ScrollViewer.CanContentScroll="True"
          ScrollViewer.IsDeferredScrollingEnabled="True">
    
    <ListView.View>
        <GridView>
            <GridViewColumn Header="ID" 
                            DisplayMemberBinding="{Binding DeviceName}"/>
            <GridViewColumn Header="温度"
                            DisplayMemberBinding="{Binding TemperatureFormatted}"/>
        </GridView>
    </ListView.View>
    
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel VirtualizingPanel.ScrollUnit="Pixel"/>
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
</ListView>

<!-- 虚拟化TreeView -->
<TreeView VirtualizingStackPanel.IsVirtualizing="True"
          VirtualizingStackPanel.VirtualizationMode="Recycling">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Children}">
            <TextBlock Text="{Binding Name}"/>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

3. 异步虚拟化加载

csharp

public class AsyncVirtualizedCollection<T> : ObservableCollection<T>, IList, INotifyCollectionChanged
{
    private readonly Func<int, Task<IEnumerable<T>>> _dataLoader;
    private readonly int _pageSize;
    private readonly Dictionary<int, List<T>> _loadedPages;
    private int _totalCount;
    
    public AsyncVirtualizedCollection(
        Func<int, int, Task<IEnumerable<T>>> dataLoader, 
        int totalCount, 
        int pageSize = 50)
    {
        _dataLoader = (page) => dataLoader(page * pageSize, pageSize);
        _totalCount = totalCount;
        _pageSize = pageSize;
        _loadedPages = new Dictionary<int, List<T>>();
    }
    
    // 重写索引器实现虚拟化
    public new T this[int index]
    {
        get
        {
            int page = index / _pageSize;
            int pageIndex = index % _pageSize;
            
            if (!_loadedPages.ContainsKey(page))
            {
                // 异步加载页面
                LoadPageAsync(page).Wait();
            }
            
            return _loadedPages[page][pageIndex];
        }
        set => base[index] = value;
    }
    
    private async Task LoadPageAsync(int page)
    {
        var data = await _dataLoader(page);
        _loadedPages[page] = data.ToList();
        
        // 触发UI更新
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(
            NotifyCollectionChangedAction.Reset));
    }
    
    // 实现其他必要方法...
}

// 使用示例
public class DataService
{
    public async Task<IEnumerable<DeviceData>> GetDevicesAsync(int skip, int take)
    {
        // 模拟数据库查询
        await Task.Delay(100);
        
        return Enumerable.Range(skip, take)
            .Select(i => new DeviceData
            {
                DeviceName = $"Device_{i}",
                Temperature = 20 + i % 30
            });
    }
}

三、性能优化技巧

1. 绑定优化

csharp

// 1. 使用延迟绑定
public class DelayedBindingHelper
{
    public static readonly DependencyProperty DelayedTextProperty =
        DependencyProperty.RegisterAttached(
            "DelayedText",
            typeof(string),
            typeof(DelayedBindingHelper),
            new FrameworkPropertyMetadata(
                null,
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                OnDelayedTextChanged,
                null,
                false,
                UpdateSourceTrigger.LostFocus));
    
    // 2. 绑定验证和转换优化
    public class TemperatureConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is double temp)
            {
                return $"{temp:F2} °C";
            }
            return string.Empty;
        }
        
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is string str && double.TryParse(str, out double temp))
            {
                return temp;
            }
            return 0.0;
        }
    }
}

2. 内存管理

csharp

public class MemoryOptimizedListBox : ListBox
{
    // 实现自定义虚拟化面板
    protected override void PrepareContainerForItemOverride(
        DependencyObject element, object item)
    {
        base.PrepareContainerForItemOverride(element, item);
        
        // 为可见项设置数据上下文
        if (element is FrameworkElement frameworkElement)
        {
            frameworkElement.DataContext = item;
        }
    }
    
    protected override void ClearContainerForItemOverride(
        DependencyObject element, object item)
    {
        // 清理资源
        if (element is FrameworkElement frameworkElement)
        {
            frameworkElement.DataContext = null;
        }
        
        base.ClearContainerForItemOverride(element, item);
    }
}

四、实际应用示例

监控系统示例

csharp

public class MonitoringSystem
{
    private readonly Timer _updateTimer;
    private readonly Random _random;
    private readonly DeviceViewModel _viewModel;
    
    public MonitoringSystem(DeviceViewModel viewModel)
    {
        _viewModel = viewModel;
        _random = new Random();
        _updateTimer = new Timer(UpdateData, null, 0, 1000);
    }
    
    private void UpdateData(object state)
    {
        // 模拟实时数据更新
        foreach (var device in _viewModel.Devices)
        {
            device.Temperature = 20 + _random.NextDouble() * 15;
            device.Timestamp = DateTime.Now;
        }
    }
    
    // 动态添加/移除设备
    public void AddNewDevice()
    {
        Application.Current.Dispatcher.Invoke(() =>
        {
            _viewModel.AddDevice($"设备_{Guid.NewGuid().ToString().Substring(0, 8)}");
        });
    }
}

配置虚拟化参数

xml

<!-- App.xaml 或 资源字典 -->
<Application.Resources>
    <Style TargetType="ListBox">
        <Setter Property="VirtualizingPanel.IsVirtualizing" Value="True"/>
        <Setter Property="VirtualizingPanel.VirtualizationMode" Value="Recycling"/>
        <Setter Property="VirtualizingPanel.CacheLength" Value="50,50"/>
        <Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
    </Style>
    
    <Style TargetType="DataGrid">
        <Setter Property="EnableRowVirtualization" Value="True"/>
        <Setter Property="EnableColumnVirtualization" Value="True"/>
        <Setter Property="RowHeight" Value="25"/>
        <Setter Property="VirtualizingPanel.ScrollUnit" Value="Pixel"/>
    </Style>
</Application.Resources>

五、最佳实践总结

  1. 动态绑定

    • 使用 ObservableCollection<T> 实现动态集合
    • 实现 INotifyPropertyChanged 实现属性变更通知
    • 使用 Dispatcher 在UI线程更新
  2. 虚拟化优化

    • 大量数据时启用虚拟化
    • 使用回收模式 (VirtualizationMode="Recycling")
    • 合理设置缓存长度
    • 避免嵌套虚拟化容器
  3. 性能监控

    csharp

    // 监控虚拟化性能
    PresentationTraceSources.DataBindingSource.Switch.Level = 
        SourceLevels.Warning | SourceLevels.Error;
    
  4. 内存优化

    • 及时释放不需要的绑定
    • 使用弱引用处理大型对象
    • 分页加载大数据集

这些技术结合使用,可以显著提升C#上位机应用程序的性能和响应速度,特别是在处理大量实时数据时。

❌
❌