【问题标题】:WPF: Binding to a (observable) DictionaryWPF:绑定到(可观察的)字典
【发布时间】:2011-05-17 11:27:06
【问题描述】:

我在我的项目中使用这个 ObservableCollection-Class:Link
我想将 RibbonMenuButton 绑定到 ObservableDictionary<string,bool>:

<r:RibbonMenuButton ItemsSource="{Binding MyDictionary}">
    <r:RibbonMenuButton.ItemContainerStyle>
        <Style TargetType="{x:Type r:RibbonMenuItem}">
            <Setter Property="IsCheckable" Value="true"/>
            <Setter Property="Header" Value="{Binding Path=Key}"/>
            <Setter Property="IsChecked" Value="{Binding Path=Value}"/>
        </style>
    </r:RibbonMenuButton.ItemContainerStyle>
</r:RibbonMenuButton>

但我得到了例外,因为内部 IDictionary-KeyValuePairs 的值属性是只读的。任何想法如何解决这个问题?

我想到了类似的东西:

<Setter Property="IsChecked" Value="{Binding Source=MyDictionary[{Binding Path=Key}]}"/>

但这不起作用,因为 {Binding} 中的 {Binding}...

【问题讨论】:

    标签: wpf binding dictionary indexing observable


    【解决方案1】:

    这不起作用,因为您的字典不被视为字典,而是被视为IEnumerable&lt;KeyValuePair&lt;string, bool&gt;&gt;。因此,每个 RibbonMenuItem 都绑定到具有只读属性 KeyValueKeyValuePair&lt;string, bool&gt;
    你可以做到两个一件事s

    1. 使用ObservableCollection&lt;Tuple&lt;string, bool&gt;&gt; 代替字典并将IsChecked 绑定到Item2
    2. 创建一个包含IsChecked 属性的小助手类,并更改您的字典以包含该类作为值并将IsChecked 绑定到Value.IsChecked

    我会选择答案二,因为所需的更改和可能的副作用较小。
    我的回答假设您希望对IsChecked 进行双向绑定。如果没有,请选择 slugster 的答案。

    【讨论】:

    • Tuple... 那是我正在寻找的课程,非常适合我!
    • narf ... Touple.Item1/2 也是只读的。所以我将使用一个辅助类,我可以避免这种情况......
    • +1,一旦 OP 详细说明并需要双向绑定,那么这是最好的选择。
    【解决方案2】:

    默认情况下,WPF 绑定是双向的。单向,看看是否能解决您的问题。

    <r:RibbonMenuButton ItemsSource="{Binding MyDictionary}">
        <r:RibbonMenuButton.ItemContainerStyle>
            <Style TargetType="{x:Type r:RibbonMenuItem}">
                <Setter Property="IsCheckable" Value="true"/>
                <Setter Property="Header" Value="{Binding Key, Mode=OneWay}"/>
                <Setter Property="IsChecked" Value="{Binding Value, Mode=OneWay}"/>
            </style>
        </r:RibbonMenuButton.ItemContainerStyle>
    </r:RibbonMenuButton>
    

    这里给你一个参考:MSDN Windows Presentation Foundation Data Binding: Part 1(具体检查页面底部的绑定模式部分)

    【讨论】:

    • 不起作用...我想将 Checkbox 的 IsChecked-State 反映到我的 ViewModel ;)
    【解决方案3】:

    如果您想在不使用辅助类的情况下将MenuItems 绑定到Dictionary&lt;string, bool&gt;,就像接受的答案所暗示的那样,这里是 minimal-change 解决方案(无需添加任何其他内容):

    • ItemContainerStyle 中定义一个Click 事件,其ClickEventHandler 将更新字典。
    • 在UserControl/Window的构造函数中声明一个字典并初始化它

    在代码中:

    MainWindow.xaml:

    <MenuItem Header="_My settings" ItemsSource="{Binding MySettings}">
        <MenuItem.ItemContainerStyle>
          <Style TargetType="{x:Type MenuItem}">
            <Setter Property="IsCheckable" Value="true"/>
            <Setter Property="Header" Value="{Binding Key, Mode=OneWay}"/>
            <Setter Property="IsChecked" Value="{Binding Value, Mode=OneWay}"/>
            <!-- this is the main line of code -->
            <EventSetter Event="Click" Handler="MySettings_ItemClick"/>
          </Style>
        </MenuItem.ItemContainerStyle>
    </MenuItem>
    

    MainWindow.xaml.cs:

    public partial class MainWindow : Window
    {
        // properties...
    
        // Declaration of the dictionary
        public Dictionary<string, bool> MySettings{ get; set; }
    
        public MainWindow()
        {
            InitializeComponent();
            // Initialize the dictionary
            MySettings = new Dictionary<string, bool>()
            {
                { "SettingOne", true}
                // Other pairs..
            };
        }
        // other things..
    
        // ClickEvent hanlder
        private void MySettings_ItemClick(object sender, RoutedEventArgs e)
        {
            MenuItem clickedItem = (sender as MenuItem);
            MySettings[clickedItem.Header as string] = clickedItem.IsChecked;
        }
    } // end of MainWindow class
    

    就是这样!一切就绪!

    感谢slugster and his answer 提供用于 OneWay 绑定的 XAML 代码 :)

    【讨论】:

      【解决方案4】:

      作为绑定到字典的这个问题的一般解决方案,我创建了一个 UpdateableKeyValuePair 并返回它而不是通常的 KeyValuePair。这是我的课:

         public class UpdateableKeyValuePair<TKey,TValue>
            {
            private IDictionary<TKey, TValue> _owner;
            private TKey _key;
            public UpdateableKeyValuePair(IDictionary<TKey, TValue> Owner, TKey Key_)
               {
               _owner = Owner;
               _key = Key_;
               }
      
            public TKey Key
               {
               get
                  {
                  return _key;
                  }
               }
      
            public TValue Value
              {
              get
                {
                return _owner[_key];
                }
             set
               {
                _owner[_key] = value;
               }
            }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-29
        • 1970-01-01
        • 2013-05-21
        • 2016-11-08
        • 2015-03-07
        • 2017-07-26
        相关资源
        最近更新 更多