Silverlight UserControl和MVVM

时间:2009-06-06 10:03:52

标签: silverlight mvvm user-controls

我有一个非常类似的问题,如this post中所述。

我有一个UserControl来封装一个地址。它包含许多基本控件,主要是文本框。然后,我在代码隐藏中为每个属性提供了依赖属性...

#region Line1

    /// <summary> 
    /// Gets or sets the Line1.
    /// </summary> 
    public string Line1
    {
        get
        {
            return (string)GetValue(Line1Property);
        }

        set
        {
            SetValue(Line1Property, value);
        }
    }

    /// <summary> 
    /// The Line1 dependency property.
    /// </summary> 
    public static readonly DependencyProperty Line1Property =
                DependencyProperty.Register(
                      "Line1",
                      typeof(string),
                      typeof(AddressControl),
                      new PropertyMetadata(OnLine1PropertyChanged));

    /// <summary>
    /// Line1Property property changed handler. 
    /// </summary>
    /// <param name="d">AddressControl that changed its Line1.</param>
    /// <param name="e">DependencyPropertyChangedEventArgs.</param> 
    private static void OnLine1PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var control = d as AddressControl;
        if (control != null)
        {
            control.OnLine1Changed((string)e.OldValue, (string)e.NewValue);
        }
    }

    /// <summary>
    /// Called when the Line1 changes.
    /// </summary>
    /// <param name="oldValue">The old value.</param>
    /// <param name="newValue">The new value.</param>
    private void OnLine1Changed(string oldValue, string newValue)
    {
        Line1TextBox.Text = newValue;
    }

    #endregion Line1

然后我在视图中使用此控件...

<myControls:AddressControl Grid.Row="0" Grid.Column="3" 
                           Line1="{Binding Path=Line1, Mode=TwoWay}"/>

这似乎是在视图模型属性更新时设置文本框值,但是我的问题是从usercontrol获取更新回到viewmodel?

根据上面的链接,我应该在控件上检查我的DataContext。 Surley的DataContext将与父级相同吗?

我希望对此的答案适用于多个嵌套级别的控件,即。 Control1中使用的Control1在Control3中使用,整个可重用性点!

让我疯了所以任何帮助都非常感激。

3 个答案:

答案 0 :(得分:3)

在MVVM中,您应该绑定到ViewModel属性,而不是绑定到控件的代码隐藏中定义的属性

答案 1 :(得分:0)

我认为我最初并没有很好地解释自己,也认为我找到了解决方案。

对于其他人;我的目标是创建一个简单的用户控件来封装一个地址(第1-4行和邮政编码,告诉你它很简单)由TextBoxes组成,用于许多页面(有时在同一页面上使用多次)。这些页面(视图)中的每一个都由MVVM模式中的ViewModel支持。到目前为止,这都是标准。我无法弄清楚的是如何更改任何这些文本框以推进到包含AddressControl的页面的ViewModel。和我在一起?

事实证明,解决方案(现在看来显而易见)是处理每个文本框丢失的焦点并更新依赖属性,这会导致绑定触发到视图模型。

private void AddressTextBox_LostFocus(object sender, RoutedEventArgs e)
    {
        switch (((TextBox)sender).Name)
        {
            case "Line1TextBox":
                Line1 = Line1TextBox.Text;
                break;

            case "Line2TextBox":
                Line2 = Line2TextBox.Text;
                break;

            case "Line3TextBox":
                Line3 = Line3TextBox.Text;
                break;

            case "Line4TextBox":
                Line4 = Line4TextBox.Text;
                break;

            case "LinePostcodeTextBox":
                Postcode = PostcodeTextBox.Text;
                break;
        }
    }

另一种选择是将文本框绑定到控件代码隐藏中的后备ViewModel,并对此更改控件。使用本地绑定而不是处理事件的效果相同。

答案 2 :(得分:0)

看起来像UserControl背后的代码用于提供控件本身绑定的属性。在这种情况下,您可能会得到一些代码,例如“this.DataContext = this”或“this.AddressLine1Control.DataContext = this”,这可能会有问题(甚至会导致SL2崩溃)。创建一个单独的类来保存数据属性,然后执行类似“this.DataContext = new MyAddressClass()”的操作。您会注意到DataContext一直向下传播到控制树,以便嵌套控件继承其父级的DataContext,如您所愿。

此外,在这里看起来您不需要DependencyProperties。创建传统的CLR属性并在数据类上实现INotifyPropertyChanged接口会更简单(假设您将数据与UserControl类分开)。这是在SL2中进行数据绑定的标准和推荐方法。