无法将数据绑定到WinForms应用程序的WPF控件中的ComboBox;设计师作品精美

vc6uscn9  于 2023-10-22  发布在  其他
关注(0)|答案(1)|浏览(103)

我有一个位于ElementHost中的WPF用户控件,因此它可以在WinForms应用程序中使用。在这个WPF用户控件上有一个ComboBox,我试图将一个相当简单的自定义类的ObservableCollection数据绑定到它。这个ObservableCollection是我的“视图模型”类(MVVM方法并不完美)的公共属性,我将其绑定到用户控件(视图),并且我有一个在设计时绑定的模拟子类。
ComboBox完全按照XAML设计器中的预期呈现,但在运行时,它完全是空的,下拉区域大约有3行高,无论我向其中添加多少项(在应用程序的生命周期中,项的数量从未改变)。还有其他控件,比如TextBlocks和自制的NumericUpDown,它们绑定到其他属性,在运行时运行得很好,但ComboBox不合作。
还有一件事,如果有关系的话--视图模型示例是从一个文件反序列化的。我还没有在序列化(反序列化)中包含我添加到它的属性,但这很重要,因为示例将被创建,然后我必须调用一个函数来完成初始化,因为构造函数被绕过,而这个完成包括初始化数据绑定项集合。我不知道这是否与问题有关,但我想我应该提到它,以防万一。
物料类。如果用户选择新语言,说明文本可能会更改:

namespace Company._DataBinding {
  
  public class FlavorOption {
    public event PropertyChangedEventHandler PropertyChanged;
    private string _descriptionText;

  public EnumFlavor Flavor { get; set; }

  public string DescriptionText {
    get { return _descriptionText; }
    set {
      if (_descriptionText != value) {
        _descriptionText = value;
        try {
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DescriptionText"));
        } catch (Exception anException) {
          throw anException;
        }
      }
    }
  }
}

用户控件的简略XAML。代码隐藏在构造函数内部调用InitializeComponent并实现IProcessOrder。否则,它不会触及任何内容,包括JuiceChoicesText、JuiceFlavorOptions、ChosenJuice或此处的控件:

<UserControl x:Class="Company._Specifics.JuiceOrderView"
         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"
         xmlns:local="clr-namespace:Company"
         xmlns:bound="clr-namespace:Company._DataBinding"
         mc:Ignorable="d" 
         d:DesignHeight="405" d:DesignWidth="612">
<Grid Background="White" d:DataContext="{d:DesignInstance Type=bound:MockProtoVM, IsDesignTimeCreatable=True}">
    <StackPanel>
        <TextBlock Text="{Binding JuiceChoicesText}" Grid.Column="2" />
        <ComboBox Margin="5" ItemsSource="{Binding JuiceFlavorOptions}"
     SelectedValuePath="Flavor" DisplayMemberPath="DescriptionText"
     SelectedValue="{Binding ChosenJuice, Mode=TwoWay}" />
    </StackPanel>
</Grid>

相关“视图模型”代码:

namespace Maf._Specifics {
  public class ProtoVM : INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;
    private string _juiceChoicesText;
    private EnumFlavor _chosenJuice;
    
    public ObservableCollection<FlavorOption> JuiceFlavorOptions { get; set; }

    public string JuiceChoicesText {
      get { return _juiceChoicesText; }
      set {
        if (_juiceChoicesText != value) {
          _juiceChoicesText = value;
          NotifyListeners();
        }
      }
    }

    public EnumFlavor ChosenJuice {
      get { return _chosenJuice; }
      set {
        if (_chosenJuice != value) {
          _chosenJuice = value;
          NotifyListeners();
        }
      }
    }

    public ProtoVM() {
      FinishInitialization();
    }

    public void FinishInitialization() {
      JuiceChoicesText = "Choose your juice flavor:";

      if (JuiceFlavorOptions == null) {
        JuiceFlavorOptions = new ObservableCollection<FlavorOption> {
         new FlavorOption { Flavor = EnumFlavor.CHERRY, DescriptionText = "Cherry" },
         new FlavorOption { Flavor = EnumFlavor.ORANGE, DescriptionText = "Orange" },
         new FlavorOption { Flavor = EnumFlavor.GRAPE, DescriptionText = "Grape" }
      };

      ChosenJuice = EnumFlavor.CHERRY;
    }

    protected void NotifyListeners([CallerMemberName] string propertyName = "") {
      try {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      } catch (Exception anException) {
        throw anException;
      }
    }
  }
}

在其父控件中设置用户控件。在数据绑定之后,不会向ComboBox(的DataContext)添加或从ComboBox(的DataContext)删除任何选项:

var juiceOrderHost = new WPFWrapperUC();
var orderJuiceTab = new TabPage(tabName);
_juiceOrderView = new JuiceOrderView();
juiceOrderHost.SetChild(_juiceOrderView);
      orderJuiceTab.Controls.Add((UserControl)juiceOrderHost);
tbcThingsToOrder.TabPages.Add(orderJuiceTab);
...
_juiceOrderKindaVM.FinishInitialization();  // _juiceOrderKindaVM is a ProtoVM
_juiceOrderView.DataContext = _juiceOrderKindaVM;

WinForms UserControl,它上面只有一个System.Windows.Forms.Integration.ElementHost:

namespace Company {
  public partial class WPFWrapperUC : UserControl, IProcessOrder {
    public WPFWrapperUC(UIElement hosting = null) {
      InitializeComponent();

      if (hosting != null)
        SetChild(hosting);
    }

    public void SetChild(UIElement hosting) {
      elhHostForWPFControl.Child = hosting;
    }

    // ...various methods that forward calls to
    //  IProcessOrder methods to elhHostForWPFControl.Child,
    //  should it be a IProcessOrder, which JuiceOrderView is. 
  }
}

mock:

namespace Company._DataBinding {
  public class MockProtoVM : ProtoVM {
    public MockProtoVM() : base() {
      JuiceChoicesText = "User sees different text at runtime, like 'Choose your juice flavor:'";
      ChosenJuice = EnumFlavor.ORANGE;
    }
  }
}

我错过了什么?谢谢...

xeufq47z

xeufq47z1#

经过更多的研究/spitballing,事实证明,在上面显示的DataContext赋值之前,DataContext在FinishInitialization被调用之前就被赋值给了ProtoVM示例,因此JuiceFlavorOptions为null。然后它在同一个示例上再次调用FinishInitialization,但显然设置JuiceFlavorOptions还不够?然后它将示例分配给DataContext,这修复了TextBlock,但没有修复ComboBox。至少,这是我对发生的事情的最佳猜测。
此外,我的FlavorOption.DescriptionText的翻译/交换需要的不仅仅是迭代JuiceFlavorOptions和更新每个FlavorOption的DescriptionText值。这将显示正确的文本时,选择一个新的选项,但下拉菜单仍将有所有旧选项的文本。您必须清除JuiceFlavorOptions并使用新的FlavorOption示例及其新的DescriptionText值重新填充它。为了使ComboBox看起来不被选中,你必须调用ChosenJuice上的属性changed delegate来完全更新绑定:

JuiceFlavorOptions.Clear();
  // French
  JuiceFlavorOptions.Add(new FlavorOption { Flavor = EnumFlavor.CHERRY, DescriptionText = "Cerise" });
  JuiceFlavorOptions.Add(new FlavorOption { Flavor = EnumFlavor.ORANGE, DescriptionText = "Orange" });
  JuiceFlavorOptions.Add(new FlavorOption { Flavor = EnumFlavor.GRAPE, DescriptionText = "Raisin" });
  NotifyListeners("ChosenJuice");

希望这能帮助那些设法进入我奇怪处境的人。

相关问题