【问题标题】:Multiple ItemSources binding多个 ItemSources 绑定
【发布时间】:2013-12-13 13:54:36
【问题描述】:

我不太擅长整个 MVVM 设计模式。虽然我觉得这个项目会从中受益,但请记住,这个项目是从 Winforms 转换而来的,当时我只是在学习 WPF。话虽如此,该项目的想法是键盘楔子和键盘挂钩。当程序加载时,主窗口变为不可见,系统托盘上的图标允许该主窗口再次可见。当主窗口可见时,它的中心有一个列表框,允许分配/定义楔形和热键。仅供参考,我将热键称为我从键盘挂钩监控的键。所以假设我正在监控 HotKeys F13-F15,并且我有 2 个键盘楔块。 Item 模板视图很简单。

<UserControl x:Class="Keymon.UserControls.HotkeyConfigurationView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid Margin="3,0">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="3*" />
            <ColumnDefinition Width="2*" />
        </Grid.ColumnDefinitions>
        <TextBlock Text="{Binding Key}" TextWrapping="Wrap" />
        <TextBlock Grid.Column="1" Text="{Binding Path}" HorizontalAlignment="Right" TextWrapping="Wrap" />
    </Grid>
</UserControl>

或者简单地将 2 个文本块并排绑定到 Key 和 Path。

我让我的 Hotkeys 和 KeyboardWedges 实现了这个

public interface IMyAdvancedListItem
{
    string Key { get; }
    string Path { get;  }
    string Parameters { get; }
}

当我的程序第一次启动时,我会检查我在哪台计算机上,这会给我一个合适的热键和键盘楔形列表。我将它们添加到正确的列表中,然后收集两个值的列表并将它们转换为 IMyAdvancedListItem ... 我最终将其移至 ModelView 以获取 MyAdvancedList

public class MyAdvancedListViewModel
{
    public List<Keymon.ValueTypes.IMyAdvancedListItem> Keys
    {
        get
        {
            System.Collections.Generic.List<Keymon.ValueTypes.IMyAdvancedListItem> list = new System.Collections.Generic.List<ValueTypes.IMyAdvancedListItem>();
            list.AddRange(Globals.MonitoredKeys.Values.Cast<Keymon.ValueTypes.IMyAdvancedListItem>());
            list.AddRange(Globals.SerialPortWedges.Values.Cast<Keymon.ValueTypes.IMyAdvancedListItem>());
            return list;
        }
        set
        {
        }
    }

    public MyAdvancedListViewModel()
    {
    }

}

最后,当用户双击列表框项目时,我让它打开正确的配置对话框,然后更新正确的列表。在它更新列表后,我告诉它刷新项目(似乎没有做任何事情)

    private void ListBox_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        var keyListBox = sender as ListBox;
        var temp = keyListBox.SelectedItem as Keymon.ValueTypes.IMyAdvancedListItem;
        var index = keyListBox.SelectedIndex;

        if (Globals.SerialPortWedges.ContainsKey(temp.Key))
        {
            if (temp.Key == "MSR")
                ConfigurationHelper.ConfigureWedge(temp.Key);
            else
                ConfigurationHelper.ConfigureWedgeEx(temp.Key);
        }
        else
        {
            ConfigurationHelper.ConfigureHotKey(temp as HotkeyConfiguration);
        }
        keyListBox.Items.Refresh();
        keyListBox.SelectedIndex = index;
    }

现在您可能想得很好,只需实现 INotifyCollection.. 就完成了。我什至尝试过 INotifyProperty。我认为最后这一切都可以归结为我只是在猜测我应该做什么而没有 100% 了解我真正在做什么。我的两个列表中的几行重要代码仅供参考。

public class GlobalHotKeys : INotifyCollectionChanged, INotifyPropertyChanged, IEnumerable
{
    public GlobalHotKeys()
    {
    }
    public HotkeyConfiguration this[int key]
    {
        get
        {
            return MonitoredKeys[key];
        }
        set
        {
            MonitoredKeys[key] = value;
            NotifyCollectionChanged(NotifyCollectionChangedAction.Replace, value);
            NotifyPropertyChanged("Keys");
        }
    }

    private Dictionary<int, HotkeyConfiguration> MonitoredKeys = new Dictionary<int, HotkeyConfiguration>();
    public IEnumerable<HotkeyConfiguration> Values { get { return MonitoredKeys.Values; } }

    #region Notifications
    private void NotifyCollectionChanged(NotifyCollectionChangedAction action, object affectedObject)
    {
        if (CollectionChanged != null)
        {
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, affectedObject));
        }
    }
    public event NotifyCollectionChangedEventHandler CollectionChanged;
    private void NotifyPropertyChanged(string property)
    {
        if(PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

}

这是我的楔子的代码

public class GlobalWedges : IEnumerable, INotifyCollectionChanged
{
    public GlobalWedges()
    {
        wedges = new Dictionary<string, KeyboardWedgeConfiguration>();
    }
    public KeyboardWedgeConfiguration this[string key]
    {
        get
        {
            if (wedges.ContainsKey(key))
                return wedges[key];
            else
                return null;
        }
        set
        {
            wedges[key] = value;
            NotifyCollectionChanged(NotifyCollectionChangedAction.Replace, value);
        }
    }

    private Dictionary<string, KeyboardWedgeConfiguration> wedges;
    public IEnumerable<KeyboardWedgeConfiguration> Values { get { return wedges.Values; } }

    #region Notifications
    private void NotifyCollectionChanged(NotifyCollectionChangedAction action, object affectedObject)
    {
        if (CollectionChanged != null)
        {
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, affectedObject));
        }
    }
    public event NotifyCollectionChangedEventHandler CollectionChanged;
    #endregion

}

我认为您不需要上述列表中项目的代码,所以这里只是类大纲。

public class KeyboardWedgeConfiguration : Keymon.ValueTypes.IMyAdvancedListItem, Keymon.ValueTypes.Saveable, IDisposable
public class HotkeyConfiguration : Keymon.ValueTypes.IMyAdvancedListItem

对不起所有的代码,但有太多总比不够好。哦,我可能忘记了。我必须关闭我的程序而不是重新打开它,然后才能看到对热键列表或键盘楔形所做的更改。我知道他们正在更新,因为如果我更新一个键说打开一个计算器,那么它就会这样做。有什么帮助吗?

编辑

仅此列表的图片。在这个屏幕截图之后,我编辑了 F13 以打开 calc.exe,但列表仍然看起来像这样。

为了显示实际更新,我必须退出我的应用程序,然后重新启动它。这就是我希望程序在刷新时所做的。

【问题讨论】:

  • System.Collections.Generic.List&lt;Keymon.ValueTypes.IMyAdvancedListItem&gt; list = new System.Collections.Generic.List&lt;ValueTypes.IMyAdvancedListItem&gt;(); - 人类历史上最好的 C# 代码行。
  • 你有没有 gui 的截图?
  • 所以它只是你有问题的刷新?
  • 如果是这样,我想我们可以参考HighCore的评论。每次在 ViewModel 中调用 getter 时,您都会创建一个新列表。当您在集合已绑定的运行时返回完全不同的/新集合时,它会破坏绑定。相反,本地化集合,并在需要时更新集合。此外,检查输出窗口中的绑定表达式错误。
  • @NETscape 是的。那就是问题所在。我可以更改该列表中的每个项目,但它不会刷新。

标签: c# wpf binding listbox


【解决方案1】:

问题不是(或者不是因为我帮助了你)列表没有在 GUI 上刷新的事实,而是你正在创建绑定到 UI 的 ItemsSource 的副本,更改那个副本,什么也不做。

这里是您制作副本的地方:

var temp = keyListBox.SelectedItem as Keymon.ValueTypes.IMyAdvancedListItem;
var index = keyListBox.SelectedIndex;

然后在ConfigurationHelper.Configure____(temp.Key) 中,您将更改或更新此列表副本。此时,您期望对列表所做的更改在绑定的 ItemsSource 中生效;但是,由于它是一个副本,因此在您更新绑定列表之前实际上不会发生任何事情!

您需要做的就是让您的 ConfigurationHelper.Configure_____(temp.Key) 返回更改的项目,然后获取该项目并更新绑定的 ViewModel 的 Keys 集合并通知 GUI 该集合已更改。

注意:这个问题的问题已在私人电子邮件中完全解决,但这是我提供的信息,让 Robert 开始走上正轨。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-04
    • 2018-07-10
    • 1970-01-01
    • 1970-01-01
    • 2015-09-25
    • 2014-03-21
    • 2013-04-13
    相关资源
    最近更新 更多