【问题标题】:Binding C# WPF controls to a dictionary将 C# WPF 控件绑定到字典
【发布时间】:2011-09-28 23:21:09
【问题描述】:

嗨 :) 我刚刚学习 C# 和 WPF,我需要编写一个工具:

  1. 加载数据文件(字符串键、整数值)
  2. 将数据绑定到 WPF UI 以进行编辑
  3. 保存新的数据文件

我的想法是最好有一本字典。 数据仅从文件加载一次,并且仅使用 WPF 控件进行更改。 我已经尝试了很多东西,但是当我将数据绑定到控件时,我仍然会遇到障碍。 我一直在使用该工具的简化版本——如下所示。 数据绑定到 WPF 控件,但没有更改事件来更新字典。 我还没有找到一个可以效仿的好榜样。 有人可以解释如何让字典更新吗? 该策略是否正确? - 使用字典 - 使用 DataContext。 如果您想查看完整的项目和 UI - 底部有一个链接。 我已经工作了很多天......有进步,但我太慢了;) 干杯 丹尼

MainWindow.xaml

<Window x:Class="configGen.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="200" Width="150">
<StackPanel Margin="20" Width="80">
    <TextBox Text="{Binding [item1]}" />
    <TextBlock Text="{Binding [item1]}" />
    <TextBox Text="{Binding [item2]}" />
    <TextBlock Text="{Binding [item2]}" />
    <TextBox Text="{Binding [item3]}" />
    <TextBlock Text="{Binding [item3]}" />
    <Slider Value="{Binding [item4]}" Minimum="0" Maximum="256" />
    <TextBlock Text="{Binding [item4]}" />
</StackPanel>    

MainWindow.xaml.cs

namespace configGen
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            dataClass record = new dataClass();
            DataContext = record.generate();
        }
    }

    public class dataClass
    {
        public Dictionary<string, int> generate()
        {
            Dictionary<string, int> _data = new Dictionary<string, int>();
            _data.Add("item1", 100);
            _data.Add("item2", 120);
            _data.Add("item3", 140);
            _data.Add("item4", 160);
            return _data;
        }
    }
}

链接到完整项目...

http://www.baytower.ca/btsRV7config.zip


感谢大家的所有好评!! 我会回去工作:)

【问题讨论】:

标签: c# wpf binding dictionary


【解决方案1】:

我不会使用字典作为DataContext,而是创建一个自定义对象,例如MainViewModel。给它对应于 item1、item2 等的属性,除了给它们适当的名称。然后使用&lt;TextBox Text="{Binding MyPropertyName}" /&gt;。要处理更新,您可以将 DataContext 设置为新的 MainViewModel 对象,也可以设置类以广播属性更改。你可以通过课堂上的INotifyPropertyChangeddependency properties 来做到这一点。

至少这就是您想要实现的目标。如果您要显示任意数量的控件,则需要一些不同的东西。

【讨论】:

  • 基于这个问题,我认为这个用户还没有准备好解决 MVVM 模式......只是说
  • 大声笑,这是真的。我是初学者,所以我应该做出一些妥协以保持简单。我喜欢字典的地方是我的索引变成了一个字符串键——而不是一个任意数字。我想我将有 100 个命名项目绑定到各种控件(滑块、编辑框、单选按钮)……列表是固定的(或多或少)但它很长。将每个项目设为属性对我来说可能是一个好方法,但输入会很多;)感谢您的回答。
【解决方案2】:

字典绝对不是在 WPF 中进行双向数据绑定的便捷方式。似乎ObservableCollection 更适合您的要求。

类似:

public class ItemsList : ObservableCollection<Item>
{
    public ItemsList() : base()
    {
        Add(new Item("item 1", 100));
        Add(new Item("item 2", 120));
        Add(new Item("item 3", 140));
        Add(new Item("item 4", 160));
    }
  }

Item 是一个具有名称和值属性的简单类。我在这里省略了它,因为它是不言自明的。

这里的优点是您可以绑定到动态数量的项目,而不仅仅是强制声明的项目。

将数据上下文绑定到它后,您将获得双向数据绑定的自动属性通知。

当然,您的 XAML 必须更改以适应与集合的绑定。可能是一个ItemsControl 将那个集合作为它的ItemsSource

【讨论】:

  • 如果他想要一些是TextBoxes 和一些是Sliders 是行不通的。
【解决方案3】:

这是我将如何做的一个例子。

主类(代码隐藏)

 /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private List<MyObject> _myObjects;
        public List<MyObject> MyObjects
        {
            get { return _myObjects; }
            set 
            {
                _myObjects = value;
                if(PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("MyObjects"));
                }
            }
        }


    public MainWindow()
    {
        MyObjects = new List<MyObject>();

        // Add 20 records for sample data
        for (int i = 0; i < 20; i++)
        {
            MyObject o = new MyObject();
            o.Label = string.Format("Key{0}", i);
            o.MyValue = string.Format("Value{0}", i);    
            MyObjects.Add(o);
        }
        InitializeComponent();
        DataContext = this;
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

中学班

public class MyObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private string _label;
    public string Label
    {
        get { return _label; }
        set
        {
            _label = value;
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Label"));
            }
        }
    }

    private string _myValue;
    public string MyValue
    {
        get
        {
            return _myValue;
        }
        set
        {
            _myValue = value;
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("MyValue"));
            }
        }
    }
}

XAML 文件

<Window x:Class="WpfApplication4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <DataTemplate x:Key="listboxstyle">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
                <TextBlock Text="{Binding Path=Label}" />
                <TextBox Grid.Column="1" Text="{Binding Path=MyValue}" />
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <Grid>       

        <ListBox
            ItemsSource="{Binding Path=MyObjects}"
            ItemTemplate="{StaticResource listboxstyle}"
            />

    </Grid>
</Window>

【讨论】:

  • 请注意,如果您想要自动 UI 更新以从集合中添加/删除项目,请将您的列表更改为 ObservableCollection
  • 感谢您的详细回答。每个 UI 控件都将绑定到特定的 MyObject 实例。我猜列表中的每个 MyObject 都由一个数字索引 - 而不是字典键字符串。使用数字而不是名称将是一个合理的折衷方案。控件种类繁多,因此我需要手动索引每个对象。感谢您展示了 PropertyChanged 应该如何工作的示例……这对我有很大帮助。
  • 我对这个问题有点晚了,但我想做类似的事情。查看“主类”代码,它是否只会通过“MyObjects = new List();”这一行引发属性更改事件?向“MyObjects”添加项目时如何引发事件?
【解决方案4】:

我已经尝试了 tsell 的示例,在列表中使用了他的课程。列表只是生成和管理固定数量元素的一种便捷方式。 Item1 WPF 控件绑定到 Item1 对象及其值。该对象是通过其索引号找到的。在这种情况下,绑定和 dataContext 对我来说非常简单(作为初学者)。它有效,但我不确定这是否是一种优雅的方式。

public MainWindow()
{
    MyObjects = new List<MyObject>();

    MyObject item1 = new MyObject();
    item1.MyValue = string.Format("100");
    MyObjects.Add(item1);

    MyObject item2 = new MyObject();
    item2.MyValue = string.Format("120");
    MyObjects.Add(item2);

    MyObject item3 = new MyObject();
    item3.MyValue = string.Format("140");
    MyObjects.Add(item3);

    MyObject item4 = new MyObject();
    item4.MyValue = string.Format("160");
    MyObjects.Add(item4);

    InitializeComponent();
    DataContext = this;
}

xaml

<Window x:Class="WpfApplication4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel Margin="20" Width="80">
        <TextBox Text="{Binding MyObjects[0].MyValue}" />
        <TextBlock Text="{Binding MyObjects[0].MyValue}" />
        <TextBox Text="{Binding MyObjects[1].MyValue}" />
        <TextBlock Text="{Binding MyObjects[1].MyValue}" />
        <TextBox Text="{Binding MyObjects[2].MyValue}" />
        <TextBlock Text="{Binding MyObjects[2].MyValue}" />
        <Slider Value="{Binding MyObjects[3].MyValue}" Minimum="0" Maximum="256" />
        <TextBlock Text="{Binding MyObjects[3].MyValue}" />
    </StackPanel>
</Window>

顺便说一句,我会将 MyValues 更改为 int ..它们都是 int 数字。现在它是一个字符串。

【讨论】:

    猜你喜欢
    • 2011-03-27
    • 2016-11-20
    • 2010-11-09
    • 1970-01-01
    • 2011-01-23
    • 1970-01-01
    • 1970-01-01
    • 2014-10-09
    • 1970-01-01
    相关资源
    最近更新 更多