在XAML

时间:2015-09-30 16:49:51

标签: c# wpf xaml mvvm data-binding

我尝试设置一个ComboBox,其中的选项是从字符串列表中绑定的,其默认选择值是从设置中绑定的,并且其选择的事件处理程序已更改。

我想像使用XAML一样配置它:

    <ComboBox Name="RoutesComboBox"
              ItemsSource="{Binding Routes}"
              SelectedItem="{Binding DefaultRoute}" 
              SelectionChanged="RouteFilter_SelectionChanged" />

但是当我在启动时这样做时会抛出错误:

  

未处理的类型异常   &#39; System.Reflection.TargetInvocationException&#39;发生在   PresentationFramework.dll

如果我只在XAML中执行某些操作,那么要么在C#中以编程方式设置SelectionChanged事件或ItemsSource,就像下面一样正常。但是我有很多这些组合框,所以我宁愿在XAML中直接做。

<ComboBox Name="RoutesComboBox"
          ItemsSource="{Binding Routes}"
          SelectedItem="{Binding DefaultRoute}" />

用这个C#:

public IEnumerable<string> Routes
{
    get { return LubricationDatabase.GetRoutes(); }
}

public string DefaultRoute
{
    get { return MySettings.Default.DefaultRoute; }
    set { } /* side question: without this, it throws a parse exception. Any idea why? */
}

public MainWindow()
{
     this.DataContext = this;
     InitializeComponent();

     RoutesComboBox.SelectionChanged += RouteFilter_SelectionChanged;
 }

我还尝试了here找到的解决方案:

private string _defaultRoute;
public string DefaultRoute
{
    get { return MySettings.Default.DefaultRoute; }
    set
    {
        if (_defaultRoute != value)
        {
            _defaultRoute = value;

            // this fires before `SelectedValue` has been 
            // updated, and the handler function uses that,
            // so I manually set it here.
            RoutesComboBox.SelectedValue = value;
            SelectionChangedHandler(); 
        }
    }
}

这是可以的,但是当我可以以编程方式分配SelectionChanged事件时,它是相当笨重的,可能还有更多值得的工作。

如果可能的话,我想再次使用XAML,因为我有很多这些ComboBox并在C#中将它们全部初始化,看起来很糟糕。

有什么想法吗?

1 个答案:

答案 0 :(得分:2)

当用户更改选择时,如果您不打算更新项目,为什么绑定SelectedItem?不确定你的事件处理程序在做什么,但我有一个工作解决方案就像你想要的那样。

简而言之,您需要使用支持字段跟踪DefaultRoute。此外,您需要在视图模型中所选项目发生更改时通知UI;顺便说一下,你似乎没有做过什么,MVVM。如果您打算以某种方式更新视图,则应该只是挂钩选择已更改的事件。应在视图模型DefaultRoute setter

中处理所有其他更改

XAML

<ComboBox Name="RoutesComboBox"
      ItemsSource="{Binding Routes}"
      SelectedItem="{Binding DefaultRoute}" 
      SelectionChanged="RouteFilter_SelectionChanged" />

代码

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public IEnumerable<string> Routes
    {
        get
        {
            return new string[] { "a", "b", "c", "d" };
        }
    }

    public string DefaultRoute
    {
        get
        {
            return _defaultRoute;
        }
        set
        {
            _defaultRoute = value;
            // Handle saving/storing setting here, when selection has changed
            //MySettings.Default.DefaultRoute = value;
            NotifyPropertyChanged();
        } 
    }

    public MainWindow()
    {
        this.DataContext = this;
        InitializeComponent();

        DefaultRoute = MySettings.Default.DefaultRoute;
    }

    private string _defaultRoute;

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private void RouteFilter_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {

    }
}

public static class MySettings
{
    public static class Default
    {
        public static string DefaultRoute = "a";
    }
}