1

我正在使用 MVVM 设计一些复杂的用户控件。UserControls 的数据上下文处理所有逻辑并将 UserControl 交互的结果提供给控件的使用者。

我面临的问题是,看起来 internal 不适用于绑定,如果我尝试绑定到非公共绑定的源属性不起作用。如果我必须打开(amek public)我的 VM 顶部的所有源属性能够绑定它们,那么我将打开 UserControl 和使用者的内部:

  1. 对使用什么属性感到困惑。
  2. 可以使用不供外部使用的属性来破坏事物。

有任何想法吗?

提前致谢。

编辑:好吧,看起来来源必须始终是公开的,对吧但是我仍然面临公开内部信息的问题。有什么解决办法吗?

例子:

您创建一个通用的用户控件。该控件应该是一个黑盒,它接受最终用户提供的查询,向他显示(以某种方式)查询返回的行,并让 UserControl 使用者获取选定的值。该控件是使用显示行的组合框实现的。

UserControl 位于 UserControl.xaml 中,并且有一个带有 UserControl 的 ViewModel 的 UserControlVM.cs 文件。

ViewModel 包含要执行的查询、查询返回的项目列表和所选项目。项目列表和选定项目是公开的,以便能够绑定到 UserControl。

消费者在其窗口内使用 UserControl 的一个实例,在其窗口视图模型内使用 UserControlVM 的一个实例。我面临的问题是最终用户有权访问查询返回的项目列表,而他只应该有权访问所选项目。

4

3 回答 3

0

我找到了一种解决方案(但如果您的 ViewModel 需要构造函数参数,我会向您推荐这不起作用)。

  1. 在保持绑定属性公开的同时将 ViewModel 设为内部。
  2. 创建一个类“UserControlData”,其中包含用户控件将提供给最终用户的数据
  3. 通过 UserControl 依赖属性提供该类的实例。
  4. 用户控件使用者必须在其视图模型中绑定 UserControlData 实例才能获得用户控件结果。
于 2012-04-12T13:13:50.770 回答
0

该类的所有属性目标都Binding必须是公共的

这是一个可能的替代解决方案:

您的DataContext(如果是 a ViewModel)很可能实现INotifyPropertyChanged. 如果是这样,那么当您在 上设置DataContext( ViewModel) 时UserControl,只需订阅PropertyChanged事件处理程序,然后在您的代码隐藏中编写逻辑以根据更改的数据操作您的控件。

于 2012-04-10T11:21:20.913 回答
0

作为类的实现细节的数据不应该是公开的,但在我看来,你甚至不应该想绑定到这种类型的数据。绑定到视图的数据应该是视图模型的公共属性和命令。请记住,视图模型定义您的 UI 是什么。

用户界面不允许更改的公共属性应该只实现 getter,而不是 setter。只能在某些条件下更改的公共属性应在设置器中强制执行这些条件。视图模型应该提供并容纳所有的 UI 逻辑(属性和命令)。

您还应该将视图模型包装在测试所有这些的单元测试中。

根据评论反馈更新:

class MyViewModel : ViewModelBase
{
     private bool _showSomething;
     public bool ShowSomething
     {
         get { return _showSomething; }
         set
         {
             _showSomething = value;
             RaisePropertyChanged("ShowSomething");
             RaisePropertyChanged("TheThing");
         }
     }

     public Something TheThing
     { 
         get
         {
             if(_showSomething) { return _theThing; }
             return _theOtherThing;
         }
     }

     private Something _theThing;
     private Something _theOtherThing;

}

编辑*:根据评论,以下内容可能更接近于所需内容。

public interface IQueryControl
{
    string Query { get; set; } //view passes query in
    ReadOnlyCollection<string> QueryResultDescriptions { get; } //bind to combo items
    string SelectedQueryDescription { get; set; } //bind to combo selection
    object SelectedItem { get; } //resulting object
}

public class UserControlVM : ViewModelBase, IQueryControl
{
    private string _query;
    private ObservableCollection<object> _queryResults;
    private ReadOnlyCollection<string> _externalResults;
    private object _selectedResult;

    public string Query 
    { 
        get { return _query; } 
        set 
        {
            _query = value; 
            RaisePropertyChanged("Query");
            UpdateQueryResults(); 
        }
    }

    private void UpdateQueryResults()
    {
        //Do query which allocates / updates _queryResults;
        _externalResults = new ReadOnlyCollection<string>((from entry in _queryResults select entry.ToString()).ToList<string>());
        RaisePropertyChanged("QueryResultDescriptions");
    }

    public ReadOnlyCollection<string> QueryResultDescriptions
    {
        get { return _externalResults; }
    }

    public string SelectedQueryDescription
    {
        get { return _selectedResult.ToString(); }
        set
        {
            SelectResult(value);
        }
    }

    private void SelectResult(string value)
    {
        Dictionary<string, object> lookup = _queryResults.ToDictionary<object, string>((result) => { return result.ToString(); });
        if (lookup.ContainsKey(value))
        {
            _selectedResult = lookup[value];
            RaisePropertyChanged("SelectedQueryDescription");
            RaisePropertyChanged("SelectedItem");
        }
        else
        {
            //throw something
        }
    }

    public object SelectedItem
    {
        get { return _selectedResult; }
    }

}
于 2012-04-10T12:00:32.540 回答