Usercontrol使用错误的Datacontext

时间:2012-10-10 12:11:13

标签: c# wpf binding dependency-properties datacontext

我有一个以这种方式在父控件中使用的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 });

执行时我得到一个Binding错误:

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')

似乎在子UserControl的Viewmodel上查找SelectedEntity,但应使用父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");
    }

4 个答案:

答案 0 :(得分:4)

你真的不应该在DataContext内设置UserControl的{​​{1}}。通过这样做,您可以阻止任何其他UserControl传递给DataContext,这会破坏WPF拥有单独的UI和数据层的最大优势之一。

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

我的建议?请勿在{{1​​}}中设置SelectedEntity

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

ParentViewModel

或者这个:

DataContext

或者,如果您的<Window.Resources> <DataTemplate DataType="{x:Type vm:TranslationTextInputViewModel}"> <Views:TranslationTextInput /> </DataTemplate> </Window.Resources> 包含特定于<Views:TranslationTextInput DataContext="{Binding SelectedTranslationTextInputViewModel}" /> 本身的功能且不应该是您的应用层的一部分,请将该代码放在ViewModel后面的代码中并删除完全是UserControl

答案 1 :(得分:1)

试试这个:

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

答案 2 :(得分:1)

设置DataContext后,您的绑定会使用它,所以我希望这种行为 - 在SelectedEntity.Name上寻找TranslationTextInputViewModel

有几种方法可以让它发挥作用。就个人而言,我喜欢在视图模型本身(具有视图模型属性的视图模型)中对这些关系进行建模,但在这种情况下,我可能会尝试这样做,因为感觉不愉快:

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

答案 3 :(得分:0)

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