用户控件MVVM中的执行方法

时间:2011-08-08 17:58:23

标签: c# wpf mvvm user-controls

我正在开发我的第一个MVVM应用程序,并且无法使其正常工作。

在我的主窗口中,我有一个按钮,它执行一个返回自定义数据表类型对象的SQL命令。

该窗口还包含一个用户控件,该控件由一些列标题和一个托管DataGridView的窗体组成。我需要以某种方式告诉用户控件执行一个将数据传递给DataGridView的方法,以便它可以更新它的值。

我尝试在我的WPF网格控件上创建一个依赖属性,该属性绑定到我的viewmodel的数据,但它没有正确更新。

我怎样才能让它发挥作用?

- 编辑 -

这是我的LiteGrid用户控件的XAML -

<UserControl x:Class="ReportUtility.Controls.LiteGrid.LiteGrid"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
         xmlns:lite="clr-namespace:ReportUtility.Controls.LiteGrid"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300"
         DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="30"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <ScrollViewer x:Name="_scroll" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden">
        <ItemsControl ItemsSource="{Binding Columns}" Grid.Row="0" Background="AliceBlue">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate> 
                        <StackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </ScrollViewer>
    <WindowsFormsHost Background="White" Grid.Row="1">
        <lite:LiteGridView x:Name="_liteGridView"/>
    </WindowsFormsHost>
</Grid>

我的主要观点模型是:

public class MainWindowViewModel : DependencyObject
{
    private readonly ILiteTableSource _source;

    public ICommand ExecuteQueryCommand { get; set; }
    public LiteGridViewModel Grid { get; set; }
    public string SqlCommandText { get; set; }

    public MainWindowViewModel(ILiteTableSource source)
    {
        this.ExecuteQueryCommand = new ExecuteQueryCommand(this);

        _source = source;
        _source.DataArrived+=new Action<DataSources.LiteSource.LiteTable>(_source_DataArrived);
    }

    public void ExecuteQuery()
    {
        _source.Connection = new ServerConnection();
        _source.CommandText = this.SqlCommandText;
        _source.ExecuteQuery();
    }

    public LiteTable Results
    {
        get { return (LiteTable)GetValue(ResultsProperty); }
        set { SetValue(ResultsProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Results.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ResultsProperty =
        DependencyProperty.Register("Results", typeof(LiteTable), typeof(MainWindowViewModel), new UIPropertyMetadata(null));

    void _source_DataArrived(LiteTable data)
    {

        this.Results = data;
    }
}

和XAML:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="50"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Button Grid.Row="0" Content="TestButton" HorizontalAlignment="Stretch" Command="{Binding ExecuteQueryCommand}"/>
    <TextBox Grid.Row="1" Text="{Binding Path=SqlCommandText, UpdateSourceTrigger=PropertyChanged}"/>
    <lite:LiteGrid Grid.Row="2" Data="{Binding Data, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>

2 个答案:

答案 0 :(得分:4)

由于你的LiteGridViewModelLiteGrid,为什么不直接从ViewModel执行命令?

使用您问题中发布的代码,我会:

将此添加到参考资料中,以确保使用LiteGridViewModel

绘制LiteView
<Window.Resources> <!-- Or Grid.Resources if you prefer -->
    <DataTemplate DataType="{x:Type lite:LiteGridViewModel}">
        <lite:LiteGrid />
    </DataTemplate>
</Window.Resources>

使用ContentControl替换<lite:LiteGrid ... />中的MainView控件以显示ViewModel

<ContentControl Content="{Binding Grid}" />

删除Data上的MainViewModel属性,因为它应存储在LiteGridViewModel中,而不是MainViewModel

使用MainWindowViewModel进行LiteGridViewModel工作,而不是通过视图尝试使用ViewModel

Grid = new LiteGridViewModel();

void _source_DataArrived(LiteTable data)
{
    Grid.Data = data;  // Fill property in ViewModel
    Grid.UpdateData(); // Call command on ViewModel
}

答案 1 :(得分:0)

public LiteTable Data
{
    get { return (LiteTable)GetValue(DataProperty); }
    set 
    {
        object oldvalue = Data;
        SetValue(DataProperty, value);
        OnPropertyChanged(new DependencyPropertyChangedEventArgs(DataProperty, oldvalue, value));
    }
}

// Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
    DependencyProperty.Register("Data", typeof(LiteTable), typeof(LiteGrid), new UIPropertyMetadata(null));

试试这个......