【问题标题】:WPF/MVVM Abstract Common MethodsWPF/MVVM 抽象常用方法
【发布时间】:2018-06-07 12:30:33
【问题描述】:

SO 社区,请多多包涵,因为我是新手,我还在(慢慢地)学习。我试图在网络上实施所有潜在的解决方案,但没有成功。我想我已经完全把自己与 DependencyMethods、DependencyProperties、RelayCommands、ICommand、BaseViewModels 等混淆了......

这是我的场景...我有一个 MainWindow(MainWindow) 和一个包含 UserControl(SampleUC) 的 Frame。 MainWindow 和 UserControl DataContext 指向它们各自的 ViewModel(MainWindowVM、SampleUCVM)。 MainWindowVM 和 SampleUCVM 是基本 ViewModel(BASEVM) 的子级,它通过 ObservableCollection 辅助类使用 INotifyPropertyChanged。 SampleUC 内部有一个 Combobox,它保存 SampleUCVM 中使用“fillFacility”方法构造的设施 ObservableCollection,并在使用“GetFacilityNum()”方法在 Combobox 中选择时存储 SelectedFacilityNum。

我想从 SampleUCVM 中提取方法“fillFacility”和“GetFacilityNum”,并将它们放在 BASEVM 或单独的类中,以便其他 ViewModel 可以访问和使用它们。它们将在我的整个项目中反复使用。有人可以向我解释如何做到这一点吗?感谢您的所有帮助和耐心!

SampleUC.xaml

    <Grid>
    <Label Content="Facility" HorizontalAlignment="Left" Margin="10,32,0,0" VerticalAlignment="Top" Width="87" Height="27"/>
    <ComboBox Name="cboFacilities" 
              HorizontalAlignment="Left" Margin="119,37,0,0" VerticalAlignment="Top" Width="120"
              DisplayMemberPath="FacilityName"
              SelectedValuePath="FacilityName"
              ItemsSource="{Binding Facilities}"
              SelectedValue="{Binding SelectedFacility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
              />
</Grid>

UCVM 示例

public class SampleUCVM : BASEVM
{

    #region MySQL Connection

    const string dbConnectionString = @"datasource=localhost;port=3306;Initial Catalog='optest1a1';username=root;password=";

    #endregion

    private ObservableCollection<Facilities> _facilitiesList;
    private string _selectedFacility;
    private int _selectedFacilityNum;

    public ObservableCollection<Facilities> Facilities
    {
        get { return _facilitiesList; }
        set
        {
            SetProperty(ref _facilitiesList, value, () => Facilities);
        }
    }

    public string SelectedFacility
    {
        get { return _selectedFacility; }
        set
        {
            SetProperty(ref _selectedFacility, value, () => SelectedFacility);
            if (_selectedFacility != null)
            {
                GetFacilityNum();
            }
        }
    }

    public int SelectedFacilityNum
    {
        get { return _selectedFacilityNum; }
        set { SetProperty(ref _selectedFacilityNum, value, () => SelectedFacilityNum); }
    }

    public SampleUCVM()
    {
        Facilities = new ObservableCollection<Facilities>();
        fillFacilities();
    }

    private void fillFacilities()
    {
        using (MySqlConnection con = new MySqlConnection(dbConnectionString))
        {
            Facilities = new ObservableCollection<Facilities>();
            con.Open();
            string Query = "SELECT * FROM facilities";
            MySqlCommand createCommand = new MySqlCommand(Query, con);
            MySqlDataReader dr = createCommand.ExecuteReader();
            int count = 1;
            while (dr.Read())
            {
                string FacilityName = dr.GetString(1);
                Facilities facilityname = new Facilities(count, FacilityName);
                Facilities.Add(facilityname);
                count++;
            }
            con.Close();
        }
    }

    private void GetFacilityNum()
    {
        if (SelectedFacility != null)
        {
            using (MySqlConnection con = new MySqlConnection(dbConnectionString))
            {
                con.Open();
                string Query = "SELECT Facility_ID_Num FROM facilities WHERE Facility_Name='" + SelectedFacility + "' ";
                MySqlCommand createCommand = new MySqlCommand(Query, con);
                MySqlDataReader dr = createCommand.ExecuteReader();
                int count = 1;
                while (dr.Read())
                {
                    int FacilityNum = dr.GetInt32(0);
                    SelectedFacilityNum = FacilityNum;
                    count++;
                }
                con.Close();
            }
        }
    }
}

BASEVM

    public class BASEVM : ObservableObject
{
    public BASEVM()
    {

    }
}

【问题讨论】:

  • 你的问题太宽泛了,有很多可能的答案。也就是说:恕我直言,VM应该非常简单,尤其是当程序本身变得更加复杂时。目前尚不清楚在视图模型之间共享与“设施”相关的代码有何用处,但根据您在此处发布的内容,代码似乎更有可能完全属于不同的类。然后,任何需要该功能的视图模型类都可以拥有该不同类的实例,而不是成为具有该功能的类的实例。

标签: c# wpf xaml mvvm


【解决方案1】:

我会考虑为这种事情实现一个数据访问层。例如:

public class DataAccess
{
    public ObservableCollection<Facilities> GetFacilities()
    {
        ObservableCollection<Facilities> facilities = new ObservableCollection<Facilities>();

        using (MySqlConnection con = new MySqlConnection(dbConnectionString))
        {
            con.Open();
            string Query = "SELECT * FROM facilities";
            MySqlCommand createCommand = new MySqlCommand(Query, con);
            MySqlDataReader dr = createCommand.ExecuteReader();
            int count = 1;
            while (dr.Read())
            {
                string FacilityName = dr.GetString(1);
                facilities facilityname = new Facilities(count, FacilityName);
                facilities.Add(facilityname);
                count++;
            }
            con.Close();
        }

        return facilities;
    }
}

然后,您可以在 ViewModel 类(或某些 ViewModel 基类)中包含 this 的实例。

关于您的GetFacilityNum() 方法,这也可以进入DataAccess 类,但我个人认为更好的解决方案是将Facility_ID_Num 作为您的Facilities 类的属性,如果可能的话.然后,您只需要修改 GetFacilities() 方法以将其引入,但是在应用程序中,您将始终能够在没有任何数据库调用的情况下访问它,因为它将是您的一部分 Facilities 模型。

【讨论】:

    【解决方案2】:

    你让事情变得比实际复杂得多。 ObservableCollection&lt;T&gt; 足以通知 WPF 控件到目前为止发生的更改;只需确保它与 XAML 正确绑定即可。

    这样

    public ObservableCollection<Facilities> Facilities { get { return _facilitiesList; } set { SetProperty(ref _facilitiesList, value, () => Facilities); } }

    是多余的,应该简化为

    public ObservableCollection<Facilities> Facilities { get; }

    并且只初始化一次 - 从构造函数中。

    只要您希望它位于基本视图模型中,只需将代码移到那里即可。然后从您的基本模型继承您的子模型,因此孩子将获得这样的属性作为自己的一部分。

    忘记SetValue(...),除非您注册自己的自定义DependencyProperty,这仅适用于高级场景。

    这些是起点。

    玩得开心。

    【讨论】:

      【解决方案3】:

      我同意Peter Duniho你的问题太笼统,没有明确的答案,但我想向你强调一些要点。 你的BASEVM 的用途是什么以及为什么它继承自ObservableObject

      包装对象的类,以便其他类可以通知 改变事件。 通常,此类设置为依赖属性 在 DependencyObjects 上,并允许其他类观察任何变化 在价值中

      如果你想要一个基本的通知更改功能,你可以这样做。

      public class ViewModelBase:INotifyPropertyChanged{
          public event PropertyChangedEventHandler PropertyChanged;
          protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
          {
              OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
          }
          protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
          {
              PropertyChanged?.Invoke(this, args);
          }
          protected void RaisePropertyChanged([CallerMemberName]string propertyName = null)
          {
              OnPropertyChanged(propertyName);
          }
          protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
          {
              if (Equals(storage, value)) return false;
      
              storage = value;
              RaisePropertyChanged(propertyName);
      
              return true;
          }
      }
      

      source
      之后,您从这个 ViewModelBase 类继承。当任何属性发生变化时,您会像这样触发PropertyChanged 事件:

      public int SelectedFacilityNum
      {
          get { return _selectedFacilityNum; }
          set { SetProperty(ref _selectedFacilityNum,value); }
      }
      

      我想提取方法“fillFacility”和 SampleUCVM 中的“GetFacilityNum”并将它们放在 BASEVM 或一个单独的类,它们可以被访问和使用 其他视图模型

      fillFacility 方法,如你的代码所示是处理database。据我所知,在MVVM 模式中,ViewModels 意味着在ViewModel 之间进行冥想

      视图模型充当视图和模型之间的中介, 并负责处理视图逻辑。通常,视图 模型通过调用模型中的方法与模型交互 类。然后,视图模型以表单的形式提供模型中的数据 视图可以轻松使用。视图模型从 模型,然后使数据对视图可用,并且可以重新格式化 以某种方式使视图更易于处理的数据。

      因此,我建议将 Data Access 逻辑从您的视图模型中分离到单独的 Data Access 层。例如,您可以使用Repository 模式并创建FacilityRepository。然后您可以将此存储库提供给ViewModels 需要此功能。如果你想更严格,你可以创建IFacilityRepository接口,让FacilityRepository实现它,然后你把这个接口注入到任何ViewModel需要这个功能。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-13
        • 2012-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-06
        • 1970-01-01
        相关资源
        最近更新 更多