【问题标题】:Usercontrol using wrong Datacontext使用错误数据上下文的用户控件
【发布时间】:2012-09-30 21:45:32
【问题描述】:

我有一个以这种方式在父控件中使用的 UserControl:

<Views:TranslationTextInput  Translation="{Binding SelectedEntity.Name}"/>

父控件 DataContext 是一个包含 SelectedEntity 属性的 ViewModel。

在我的子 UserControl 中,我将一个新的 ViewModel 定义为 DataContext:

    <UserControl.DataContext>
      <vm:TranslationTextInputViewModel x:Name="vm"></vm:TranslationTextInputViewModel>
    </UserControl.DataContext>

在我后面的代码中:

    public static readonly  DependencyProperty TranslationProperty = DependencyProperty.Register("Translation", typeof(Translation),typeof(UserControl));

    // .NET Property wrapper
    public Translation Translation
    {
        get { return (Translation)GetValue(TranslationProperty); }
        set { SetValue(TranslationProperty, value); }
    }


 public TranslationTextInput(){
     InitializeComponent();
     DataContext = new TranslationTextInputViewModel();
     SetBinding(TranslationProperty,   new Binding { Path = new PropertyPath     ("Translation"), Mode = BindingMode.OneWayToSource });

执行时出现绑定错误:

System.Windows.Data Error: 40 : BindingExpression path error: 'SelectedEntity' property not found on 'object' ''TranslationTextInputViewModel' (HashCode=49954236)'. BindingExpression:Path=SelectedEntity.Name; DataItem='TranslationTextInputViewModel' (HashCode=49954236); target element is 'TranslationTextInput' (Name='InputControl'); target property is 'Translation' (type 'Translation')

似乎 SelectedEntity 是在子 UserControl 的 Viewmodel 上查找的,但应该使用父 ViewModel 的 Property。我该如何解决这个问题?

编辑:

    public TranslationTextInputViewModel()
    {
        //EnglishTranslation = tranlsations["en"];
    }

    public string EnglishTranslation
    {
        get
        {
            if (!Translation.TranslationDict.ContainsKey(new CultureInfo("en").LCID))
                Translation.Translations.Add(new TranslationItem() { Text = "", Lcid = new CultureInfo("en").LCID });
            return Translation.TranslationDict[new CultureInfo("en").LCID].Text;
        }
        set
        {
            Translation.TranslationDict[new CultureInfo("en").LCID].Text = value;
        }

    }

    public string SelectedTranslation
    {
        get
        {
            if (!Translation.TranslationDict.ContainsKey(_selectedLanguage))
                Translation.Translations.Add(new TranslationItem() { Text = "", Lcid = _selectedLanguage });
            return Translation.TranslationDict[_selectedLanguage].Text;

        }

        set
        {
            Translation.TranslationDict[_selectedLanguage].Text = value;
        }
    }

    private Translation _translation;

    public Translation Translation
    {
        get
        {
            if (_translation == null)
                _translation = new Translation();
            return _translation; }
        set { _translation = value; }
    }

    private int _selectedLanguage;
    public int SelectedLanguage
    {
        get
        {
            return _selectedLanguage;
        }
    }

    public List<CultureInfo> AvailableLanguages
    {
        get
        {

            return (from x in PqsLocalization.AvailableLanguages where x.Name != "en" select x).ToList();
        }
    }

    public RelayCommand<int> LanguageChanged { get; private set; }


    private void LanguageChangedExecute(int lang)
    {
        _selectedLanguage = lang;
        RaisePropertyChanged("SelectedLanguage");
        RaisePropertyChanged("SelectedTranslation");
    }

【问题讨论】:

    标签: c# wpf binding dependency-properties datacontext


    【解决方案1】:

    试试这个:

    <Views:TranslationTextInput  Translation="{Binding SelectedEntity.Name}" DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}" /> 
    

    【讨论】:

      【解决方案2】:

      这是因为您在构造函数中将 TranslationTextInput.DataContext 设置为 TranslationTextInputViewModel。

      【讨论】:

        【解决方案3】:

        一旦你设置了DataContext,你的绑定就会使用它,所以我希望这种行为——在TranslationTextInputViewModel上寻找SelectedEntity.Name。

        有几种方法可以使其正常工作。就个人而言,我喜欢在视图模型本身(具有视图模型属性的视图模型)中对这些关系进行建模,但在这种情况下,我可能会尝试这样做,尽管感觉很不愉快:

        <Views:TranslationTextInput 
            Translation="{Binding DataContext.SelectedEntity.Name,
                          RelativeSource={RelativeSource FindAncestor,
                                          AncestorType=ParentControlType}}" />
        

        【讨论】:

        • 在(可重用)用户控件后面有一个视图模型,我做对了吗?感觉不应该是这样的……
        【解决方案4】:

        您真的不应该从UserControl 内部设置UserControl 的DataContext。通过这样做,您可以防止任何其他 DataContext 被传递给 UserControl,这会破坏 WPF 拥有独立 UI 和数据层的最大优势之一。

        在创建 UserControl 时,您将 DataContext 设置为新的 TranslationTextInputViewModel,而 TranslationTextInputViewModel 没有名为 SelectedEntity 的属性,因此您的绑定失败。

        我的建议?不要在UserControl 中设置DataContext。

        如果您希望将特定 ViewModel 用于特定 UserControl,请将其添加到您的 ParentViewModel 并将其作为 DataContext 传递,例如:

        <Window.Resources>
            <DataTemplate DataType="{x:Type vm:TranslationTextInputViewModel}">
                <Views:TranslationTextInput />
            </DataTemplate>
        </Window.Resources>
        

        或者这个:

        <Views:TranslationTextInput 
            DataContext="{Binding SelectedTranslationTextInputViewModel}" />
        

        或者如果您的ViewModel 包含特定于UserControl 本身的功能并且不应该是您的应用程序层的一部分,则将该代码放在UserControl 后面的代码中,并完全摆脱ViewModel。

        【讨论】:

        • 您好,谢谢您的解释。 Viewmodel 将仅包含控件的功能(选定语言 ...)。您是否建议我简单地在代码后面创建属性,实现 INotifyPropertyChanged 接口并将我的字段绑定到代码后面而不设置 DataContext?
        • 如果应用程序的其他部分可以影响该值,我会制作那些DependencyProperties,以便使用该控件的任何人都可以设置该值。如果它们仅在控件内部使用,我会质疑是否需要拥有它们,因为听起来它们应该是静态的,或者基于 UserControl 内的某些 UI 对象,您可以直接绑定到包含该属性的 UI 元素。
        • 应用程序的其他部分不能更改这些属性。虽然我也不能直接绑定到 ui 组件。一个翻译项(依赖属性)有一个存储不同翻译的字典。在我的用户控件中,我有一个文本框和一组按钮(每种语言一个)。如果单击按钮,则应检查它是否已经是 Dictionary 的一部分,如果不是则添加。然后显示所选语言的翻译。你对这个问题有什么建议?提前致谢?
        • @TheJoeIaut 我不确定您的确切情况,但就个人而言,如果传递给 UserControl 的 Translation 属性包含语言字典,我会在 UserControl 中编写语言按钮使用绑定到该列表的ItemsControl。如果应该在 UserControl 中定义语言词典,我会将其从 Transation 对象中完全删除,并将其放入 UserControl's 代码隐藏中。
        • (cont) 或者如果真的必须在 Translation 对象和 UserControl 中定义语言,我会将该功能添加到 UserControl 的代码隐藏中,或者添加一个 @ 987654349@ 命令到您的 UI 按钮可以绑定到的 Translation 对象,并将必要时添加的语言作为 CommandParameter 传递给它。例如,我可能让Translation 对象包含OriginalText、TranslatedText(绑定到您的TextBox)、ObservableCollection&lt;Language&gt;、ICommand AddLanguage(language) 和ICommand TranslateText(language)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-11-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多