绑定多个ViewModel

时间:2015-11-17 19:40:50

标签: c# wpf

我的wpf程序中有多个选项卡,每个选项卡都会加载一个不同的UserControl。

在我的主窗口中,我有一些项目,例如进度条和标题页眉,这些项目应该在所有UserControl中都可见。这是我的主窗口的样子

<UserControl.DataContext>
    <vm:ValuesCheck></vm:ValuesCheck>
</UserControl.DataContext>

<Grid>
  <ProgressBar Height="20" Minimum="0" Maximum="7" Padding="30" Name="pb_status" Value="{Binding pb_Value}" />
</Grid>

<TabControl>

  <TabItem Header="Introduction">
    <!--Code for My intro tab-->
  </TabItem>

  <TabItem Header="Step 1">
    <my:Step1 Loaded="Step1_Loaded" />
  </TabItem>
  <TabItem Header="Step 2" IsEnabled="{Binding step2Enabled}">
    <my:Step2 Loaded="Step2_Loaded" />
  </TabItem>
  <TabItem Header="Step 3" IsEnabled="{Binding step3Enabled}">
    <my:Step3 Loaded="Step3_Loaded" />
  </TabItem>

</TabControl>

对于每个用户控件,我已将堆栈面板的数据上下文设置为每个用户控件的不同ViewModel。堆栈面板有文本框。致电&#39; Set&#39; &#39;文本&#39;在文本框中,bound属性检查文本并设置&#39; brush&#39;属性绑定到文本框的borderbrush。因此,用户可以实时查看它们是正确还是错误。

decimal _cAS;
public decimal cAS
{
    get { return _cAS; }
    set 
    {   
        _cAS = value;
        OnPropertyChanged("cAS");

        BrushConverter converter = new BrushConverter();
        if (_cAS<= 17 || _cAS >= 19)
            CASB= (Brush)converter.ConvertFromString("#FF0000");
        else
            CASB = (Brush)converter.ConvertFromString("#008000");
    }
}

System.Windows.Media.Brush _casb;
public System.Windows.Media.Brush CASB
{
    get { return _casb; }
    set { _casb = value; OnPropertyChanged("CASB"); }
}
<TextBox Name="cAS" Text="{Binding cAS, UpdateSourceTrigger=PropertyChanged}" 
         BorderBrush="{Binding CASB, UpdateSourceTrigger=PropertyChanged}" ...>

现在我不知道如何继续。我想启用下一个选项卡,并在按下每个选项卡上的按钮时增加进度条。我在xaml背后的代码中这样做。

private void proceed3_Click(object sender, RoutedEventArgs e)
{
    var vm = DataContext as ViewModel.ValuesCheck;
    vm.step4Enabled = true;
}

我如何在后面的代码中知道正确输入了所有值。按钮的数据上下文是mainViewModel,而不是特定的ViewModel。

2 个答案:

答案 0 :(得分:0)

我认为最适合您的方法是创建一个Wizard

答案 1 :(得分:0)

对于这样的事情,我会看到类似这样的MainViewModel

public class MainViewModel
{
    ObservableCollection<ITabViewModel> Tabs { get; set; }
    int CurrentTabIndex { get; set; }
    int MaxTabIndex { get; set; }
    int Progress { get; set; }
    ICommand NextTab { get; set; }

    public MainViewModel()
    {
        Tabs = new ObservableCollection<ITabViewModel>();
        Tabs.Add(new Introduction());
        Tabs.Add(new Step1());
        Tabs.Add(new Step2());
        Tabs.Add(new Step3());

        Progress = 0;
        CurrentTabIndex = 0;
        MaxTabIndex = 0;
    }
}

NextTab命令CanExecute看起来像这样:

public bool NextTabCanExecute()
{
    // verify all tabs are valid so far
    for (int i = 0; i <= MaxTabIndex; i++)
    {
        if (Tabs[i].IsValid)
            return false;
    }

    // can't hit Next if we're on last tab    
    if (CurrentTabIndex == Tabs.Count - 1)
        return false;

    return true;
}

虽然NextTab命令可能看起来像这样

public void NextTab()
{
    if (CurrentTabIndex == Tabs.Count - 1)
        return; // on last tab already

    CurrentTabIndex++;

    // if user is on last enabled tab
    if (CurrentTabIndex == MaxTabIndex)
    {
        MaxTabIndex++;
        Progress += 100 / Tabs.Count;
    }
}

如果下一个按钮必须位于选项卡内的各个控件上,那么您可能会执行类似

的操作
foreach(ITabViewModel tab in Tabs)
{
    tab.NextButtonCommand = this.NextTab;
}

可能需要检查或调整一些额外的案例,但这应该会给你一个大致的想法。

当然,您的XAML可能还需要进行修改以支持此功能。

作为替代方案,您可以替换

ObservableCollection<ITabViewModel> Tabs  { get; set; }

使用特定对象,例如

IntroViewModel Intro { get; set; }
Step1ViewModel Step1 { get; set; }
Step2ViewModel Step2 { get; set; }
Step3ViewModel Step3 { get; set; }

bool IsStep1Enabled { get; set; }
bool IsStep2Enabled { get; set; }
bool IsStep3Enabled { get; set; }

并让您的MainViewModel分配代理人以确定应该启用什么或当您点击下一步时会发生什么

Intro.NextDelegate = this.GoToStep1;
Step1.NextDelegate = this.GoToStep2;
Step2.NextDelegate = this.GoToStep3;

Step1.IsValidChanged += delegate { IsStep2Enabled = Step1.IsValid; }
Step2.IsValidChanged += delegate { IsStep3Enabled = Step2.IsValid; }

就我个人而言,我不会这样,但这是一个选择:)