I want to write an control that behaves a bit like the CommandBar.
Using CommandBar you can write:
<CommandBar>
<CommandBar.PrimaryCommands>
<AppBarButton>B1</AppBarButton>
<AppBarButton>B2</AppBarButton>
</CommandBar.PrimaryCommands>
</CommandBar>
My control also has properties to which controls can be added within xaml.
Like this:
<Page
x:Class="TheApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:App27"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<local:MyControl>
<local:MyControl.LeftStuff>
<Button>L1</Button>
<Button>L2</Button>
</local:MyControl.LeftStuff>
<local:MyControl.MidStuff>
<Button>M1</Button>
<Button>M2</Button>
</local:MyControl.MidStuff>
<local:MyControl.RightStuff>
<Button>R1</Button>
<Button>R2</Button>
</local:MyControl.RightStuff>
</local:MyControl>
</Grid>
</Page>
So far I've come up with the following UserControl.
MyControl.xaml:
<UserControl
x:Class="TheApp.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:App27"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="400"
mc:Ignorable="d">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ItemsControl Grid.Column="0" ItemsSource="{x:Bind LeftStuff}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<ItemsControl Grid.Column="1" ItemsSource="{x:Bind MidStuff}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<ItemsControl Grid.Column="2" ItemsSource="{x:Bind RightStuff}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</UserControl>
MyControl.xaml.cs:
namespace TheApp
{
using System.Collections.ObjectModel;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
public sealed partial class MyControl: UserControl
{
public MyControl()
{
this.InitializeComponent();
}
public static readonly DependencyProperty LeftStuffProperty =
DependencyProperty.Register("LeftStuff", typeof(ObservableCollection<FrameworkElement>), typeof(MyControl), new PropertyMetadata(null));
public ObservableCollection<FrameworkElement> LeftStuff
{
get { return (ObservableCollection<FrameworkElement>)GetValue(LeftStuffProperty); }
set { SetValue(LeftStuffProperty, value); }
}
public static readonly DependencyProperty MidStuffProperty =
DependencyProperty.Register("MidStuff", typeof(ObservableCollection<FrameworkElement>), typeof(MyControl), new PropertyMetadata(null));
public ObservableCollection<FrameworkElement> MidStuff
{
get { return (ObservableCollection<FrameworkElement>)GetValue(MidStuffProperty); }
set { SetValue(MidStuffProperty, value); }
}
public static readonly DependencyProperty RightStuffProperty =
DependencyProperty.Register("RightStuff", typeof(ObservableCollection<FrameworkElement>), typeof(MyControl), new PropertyMetadata(null));
public ObservableCollection<FrameworkElement> RightStuff
{
get { return (ObservableCollection<FrameworkElement>)GetValue(RightStuffProperty); }
set { SetValue(RightStuffProperty, value); }
}
}
}
This compiles and MainPage is rendered as expected in designer.
But when I run the code I get this exception:
An exception of type 'Windows.UI.Xaml.Markup.XamlParseException' occurred in App27.exe but was not handled in user code
WinRT information: Cannot add instance of type 'Windows.UI.Xaml.Controls.Button' to a collection of type 'System.Collections.ObjectModel.ObservableCollection`1'. [Line: 16 Position: 13]
...
So what is wrong?
To answer the question myself:
the dependency properties need to be initialized so that xaml can add the elements.
public static readonly DependencyProperty ...StuffProperty =
DependencyProperty.Register(
"...Stuff",
typeof(ObservableCollection<FrameworkElement>),
typeof(MyControl),
// The property needs to be initialized
new PropertyMetadata(new ObservableCollection<FrameworkElement>())
);
Related
I want to use a custom UserControl in an ItemsControl but it is not working.
A minimalistic example:
Project.Controls.UserControl1.xaml
<UserControl x:Class="Project.Controls.UserControl1"
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:local="clr-namespace:Project.Controls"
mc:Ignorable="d"
Height="50" Width="100">
<Grid Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:UserControl1}}, Path=Text1}"/>
<Label Grid.Column="1" Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:UserControl1}}, Path=Text2}"/>
</Grid>
</UserControl>
Project.Controls.UserControl1.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace Project.Controls
{
/// <summary>
/// Interaktionslogik für UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public string Text1
{
get { return (string)GetValue(Text1Property); }
set { SetValue(Text1Property, value); }
}
public readonly DependencyProperty Text1Property =
DependencyProperty.Register("Text1", typeof(string), typeof(UserControl1));
public string Text2
{
get { return (string)GetValue(Text2Property); }
set { SetValue(Text2Property, value); }
}
public readonly DependencyProperty Text2Property =
DependencyProperty.Register("Text2", typeof(string), typeof(UserControl1));
}
}
Project.Controls.UserControl2.xaml
<UserControl x:Class="Project.Controls.UserControl2"
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:local="clr-namespace:Project.Controls.Elements"
mc:Ignorable="d"
Height="450" Width="800">
<Grid Background="Gray">
<ItemsControl x:Name="MyItemControl">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:UserControl1 Text1="{Binding Text1}" Text2="{Binding Text2}" Margin="10"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
Project.Controls.UserControl2.xaml.cs
public partial class UserControl2 : UserControl
{
public UserControl2()
{
InitializeComponent();
MyItemControl.ItemsSource = new List<MyListItem>()
{
new MyListItem("a", "b"),
new MyListItem("a", "b"),
new MyListItem("a", "b"),
new MyListItem("a", "b"),
new MyListItem("a", "b"),
new MyListItem("a", "b"),
new MyListItem("a", "b"),
};
}
}
here i have used the class MyListItem:
public class MyListItem
{
public string Text1 { get; set; }
public string Text2 { get; set; }
public MyListItem(string text1, string text2)
{
Text1 = text1;
Text2 = text2;
}
}
In the mainWindow I use UserControl2 like this:
<Window x:Class="Project.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Project"
xmlns:controls="clr-namespace:Project.Controls"
mc:Ignorable="d"
Title="Test" Height="800" Width="1280" >
<Grid>
<controls:UserControl2/>
</Grid>
</Window>
Now my problem: I either get the error
System.Windows.Markup.XamlParseException: ""Binding" cannot be set for the "Text1" property of type "UserControl1". "Binding" can be set only for a DependencyProperty of a DependencyObject."
The identifier field of a dependency property must be declared as a static field:
public static readonly DependencyProperty Text1Property =
DependencyProperty.Register(
nameof(Text1),
typeof(string),
typeof(UserControl1));
For details see Custom Dependency Properties.
Hello i am trying to initialize usercontrol with bacground which is binded in viewmodel. In model color is set but dependency property does not take it.
HeaderCropper xaml :
<UserControl x:Class="x.CustomControls.x"
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:converters="clr-x.Converters"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="300"
Width="{Binding CropperWidth,ElementName=HeaderCropper}"
Height="{Binding CropperHeight,ElementName=HeaderCropper}"
x:Name="HeaderCropper">
<Thumb x:Name="CroppableArea" BorderThickness="1" Grid.Column="0" Grid.Row="0" Background='{Binding CropperColor}' BorderBrush="Black" Opacity="0.2"
HeaderCropper class :
public static DependencyProperty ColorProperty;
static HeaderCroper()
{
ColorProperty = DependencyProperty.Register("CropperColor",
typeof(Brush), typeof(HeaderCroper), new FrameworkPropertyMetadata(null));
}
public Brush CropperColor
{
get { return (Brush)GetValue(ColorProperty); }
set
{
SetValue(ColorProperty, value);
}
}
HeaderCropper binding :
<DataTemplate>
<custom:HeaderCroper Panel.ZIndex="1" Width="50" Height="50" CropperHeight="{Binding Height,Mode=TwoWay,NotifyOnTargetUpdated=True}"
CropperWidth="{Binding Width,Mode=TwoWay,NotifyOnTargetUpdated=True}"
MaxCropperHeight="{Binding ElementName=Image,Path=RenderSize.Height}"
MaxCropperWidth="{Binding ElementName=Image,Path=RenderSize.Width}"
InfoCommand="{Binding InfoCommand}"
InfoCommandParameter="{Binding Id}"
DeleteCropperCommand="{Binding DeleteCommand}"
DeleteCropperCommandParameter="{Binding Id}"
CropperLeft="{Binding CropperLeft,Mode=TwoWay,NotifyOnTargetUpdated=True}"
CropperTop="{Binding CropperTop,Mode=TwoWay,NotifyOnTargetUpdated=True}"
MainCanvas ="{Binding ElementName=CropperCanvas,NotifyOnTargetUpdated=True}"
Canvas.Left="0"
CropperColor="{Binding CropperColor,Mode=TwoWay,NotifyOnTargetUpdated=True}"
/>
</DataTemplate>
As you can see CropperColor parameter is passed but header cropper is ignoring it and not setting color. Any ideas?
UPDATE:
As I debug on private method key press I see that color is set but it is null while usercontroll is initializing.
I'm currently working on a Windows Universal App. I'm still quite new to XAML in general but have had some experience with it.
The issue I'm having is around binding inside a UserControl. I've looked around and can't find an answer to my specific issue.
I have a XAML page that is linked to a ViewModel, this all works fine. Then on that page I'm using a UserControl that is basically just a panel with a header that contains some content. In the content of that panel I have another UserControl that basically just consists of a Label and TextBox.
When I bind things from my ViewModel to the ContentPanel UserControl everything works fine, it picks up my ViewModel context and binds correctly.
However, When I try to bind to the LabelledTextbox UserControl that is contained withing the ContentPanel the binding fails because it is just looking for the property that is on the ViewModel on the ContentPanel instead.
See below for the code I have
Page.xaml
<!--Page.xaml-->
<cc:ContentPanel PanelHeading="LEFT FOOT: Measurements" PanelHeadingBackground="{StaticResource OPCare.PanelHeader}">
<StackPanel>
<cc:LabelledTextbox LabelText="Malleoli Width" Text="test" />
<cc:LabelledTextbox LabelText="Met Head Width" />
</StackPanel>
</cc:ContentPanel>
ContentPanel.xaml
<!--ContentPanel UserControl-->
<UserControl
x:Class="OrthoticTabletApp.Controls.ContentPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:OrthoticTabletApp.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400"
x:Name="Parent">
<Grid DataContext="{Binding ElementName=Parent}">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Padding="10" Grid.Column="0" Grid.Row="0" Height="50" Background="{Binding Path=PanelHeadingBackground}">
<TextBlock Height="30" LineHeight="30" Text="{Binding Path=PanelHeading}" />
</Grid>
<Grid Padding="10" Grid.Column="0" Grid.Row="1" Background="White">
<ContentPresenter Content="{Binding Path=PanelBody}" />
</Grid>
</Grid>
</UserControl>
ContentPanel.xaml.cs
[ContentProperty(Name = "PanelBody")]
public sealed partial class ContentPanel : UserControl
{
public static readonly DependencyProperty PanelHeadingProperty = DependencyProperty.Register("PanelHeading", typeof(string), typeof(ContentPanel), new PropertyMetadata(""));
public string PanelHeading
{
get
{
return (string)GetValue(PanelHeadingProperty);
}
set
{
SetValue(PanelHeadingProperty, value);
}
}
public static readonly DependencyProperty PanelBodyProperty = DependencyProperty.Register("PanelBody", typeof(object), typeof(ContentPanel), new PropertyMetadata(null));
public object PanelBody
{
get
{
return (object)GetValue(PanelBodyProperty);
}
set
{
SetValue(PanelBodyProperty, value);
}
}
public Brush PanelHeadingBackground
{
get { return (Brush)GetValue(PanelHeadingBackgroundProperty); }
set { SetValue(PanelHeadingBackgroundProperty, value); }
}
public static readonly DependencyProperty PanelHeadingBackgroundProperty =
DependencyProperty.Register("PanelHeadingBackground", typeof(Brush), typeof(ContentPanel), new PropertyMetadata(null));
public ContentPanel()
{
this.InitializeComponent();
}
}
LabelledTextbox.xaml
<UserControl
x:Class="OrthoticTabletApp.Controls.LabelledTextbox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:OrthoticTabletApp.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="50"
d:DesignWidth="400"
x:Name="Parent">
<Grid DataContext="{Binding ElementName=Parent}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Padding="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="15" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Path=LabelText}" />
</Grid>
<Grid Grid.Column="1" Padding="10">
<TextBox Text="{Binding Path=Text}" />
</Grid>
</Grid>
</UserControl>
LabelledTextbox.xaml.cs
public sealed partial class LabelledTextbox : UserControl
{
public string LabelText
{
get { return (string)GetValue(LabelTextProperty); }
set { SetValue(LabelTextProperty, value); }
}
// Using a DependencyProperty as the backing store for LabelText. This enables animation, styling, binding, etc...
public static readonly DependencyProperty LabelTextProperty =
DependencyProperty.Register("LabelText", typeof(string), typeof(LabelledTextbox), new PropertyMetadata(null));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(LabelledTextbox), new PropertyMetadata(null));
public LabelledTextbox()
{
this.InitializeComponent();
}
}
However, When I try to bind to the LabelledTextbox UserControl that is contained withing the ContentPanel the binding fails because it is just looking for the property that is on the ViewModel on the ContentPanel instead.
If I correctly understood what you've done, some properties of your ContentPanel are bound to the data model in the page's viewmodel, and properties of your LabelledTextbox are bound to the data model in other viewmodel?
If so, you can specify the DataContext for LabelledTextbox for StackPanel which is inside the ContentPanel, just for example like this:
<cc:ContentPanel PanelHeading="{x:Bind Heading}" PanelHeadingBackground="Azure">
<StackPanel>
<StackPanel.DataContext>
<local:LabelledTextboxViewModel x:Name="VM" />
</StackPanel.DataContext>
<cc:LabelledTextbox LabelText="{x:Bind VM.Lable1}" Text="test" />
<cc:LabelledTextbox LabelText="{x:Bind VM.Lable2}" />
</StackPanel>
</local:ContentPanel>
In your page's viewmodel, you can make the data model for ContentPanel and initialize the data for example like this:
public BlankPage3ViewModel()
{
Heading = "LEFT FOOT: Measurements";
}
public string Heading { get; set; }
In the LabelledTextboxViewModel you can code for example like this:
public class LabelledTextboxViewModel
{
public LabelledTextboxViewModel()
{
Lable1 = "Malleoli Width";
Lable2 = "Met Head Width";
}
public string Lable1 { get; set; }
public string Lable2 { get; set; }
}
Usually when we follow the MVVM pattern to develop a project, the data model should not be included inside of the viewmodel, I'm here just for clear and easy delivery, the key point is that you can specify different DataContext for different controls in the same page.
I've been poking around at various links and I can't tell if I need a DependencyProperty, INotifyPropertyChanged, some kind of binding or something else.
I'm working on my first UserControl for re-use purposes. I have a UserControl that contains a label and a coloured ellipse. I want to be able to set the Ellipse colour in the windows XAML at design time. I have the following code in Visual Studio 2013 Community:
<UserControl x:Class="DMS2.LegendLabel"
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"
mc:Ignorable="d">
<StackPanel Orientation="Horizontal">
<Ellipse Name="Indicator" Height="10" Width="10" Margin="5" Fill="Aqua"/>
<Label> value </Label>
</StackPanel>
namespace DMS2
{
public partial class LegendLabel : UserControl
{
public LegendLabel()
{
InitializeComponent();
}
private Brush ellipse_color = Brushes.Azure;
public Brush LegendColor
{
get { return ellipse_color; }
set { ellipse_color = value; Indicator.Fill = ellipse_color; }
}
}
}
<Window x:Class="DMS2.ReportMonitor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom_controls="clr-namespace:DMS2"
Title="Report Monitor" Height="450" Width="850">
<StackPanel Orientation="Vertical" Name="MainPanel">
<StackPanel Orientation="Horizontal" Name="ButtonPanel">
<Button Height="25" Margin="30,0"> Refresh List</Button>
<CheckBox Margin="10"> show Reports From All Users</CheckBox>
<Grid Margin="10" Width="300">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<custom_controls:LegendLabel LegendColor="Red">Pending</custom_controls:LegendLabel>
<custom_controls:LegendLabel Grid.Column="1" LegendColor="Green">Viewed</custom_controls:LegendLabel>
<custom_controls:LegendLabel Grid.Column="2" LegendColor="Blue">Active</custom_controls:LegendLabel>
<Label Grid.Row="1">Done</Label>
<Label Grid.Column="1" Grid.Row="1">Error</Label>
<Label Grid.Column="2" Grid.Row="2">Closed</Label>
</Grid>
<Button Height="25" Margin="30,0">Close</Button>
</StackPanel>
</StackPanel>
</Window>
Using the LegendColor as shown below has now effect. How can I make the following work?
<custom_controls:LegendLabel LegendColor="Red">Pending</custom_controls:LegendLabel>
Yes, you would typically use a DependencyProperty here (snippet: propdp).
public Brush LegendColor
{
get { return (Brush)GetValue(LegendColorProperty); }
set { SetValue(LegendColorProperty, value); }
}
// Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc...
public static readonly DependencyProperty LegendColorProperty =
DependencyProperty.Register("LegendColor", typeof(Brush), typeof(LegendLabel), new PropertyMetadata(null, HandleBrushChange));
Once you have it, you would perform your set in the PropertyChanged handler (the second argument to the metadata):
private static void HandleBrushChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
LegendLabel local = (LegendLabel)d;
local.Indicator.Fill = e.NewValue as Brush;
}
I am working on my first MVVM application and am having trouble getting it to work properly.
In my main window, I have a button that executes a SQL command that returns a custom data table type object.
The window also contains a user control that consists of a some column headers and a windows forms hosted DataGridView. I need to somehow tell the user control to execute a method that passes the data to the DataGridView so it can update it's values.
I tried creating a dependency property on my WPF Grid control that is bound to the data of my viewmodel, but it is not updating properly.
How can I get this to work?
--EDIT--
Here is the XAML for my LiteGrid usercontrol -
<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>
My main view model is:
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;
}
}
And the 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>
Since you have a LiteGridViewModel to go with your LiteGrid, why not just execute the command from the ViewModel?
Using the code posted in your question, I would:
Add this to the Resources to make sure that LiteGridViewModel is drawn using LiteView
<Window.Resources> <!-- Or Grid.Resources if you prefer -->
<DataTemplate DataType="{x:Type lite:LiteGridViewModel}">
<lite:LiteGrid />
</DataTemplate>
</Window.Resources>
Replace the <lite:LiteGrid ... /> control in the MainView with a ContentControl to display the ViewModel
<ContentControl Content="{Binding Grid}" />
Remove the Data Property on the MainViewModel since it should be stored in LiteGridViewModel, not MainViewModel
And in your MainWindowViewModel work with the LiteGridViewModel instead of trying to work with the ViewModel via the View
Grid = new LiteGridViewModel();
void _source_DataArrived(LiteTable data)
{
Grid.Data = data; // Fill property in ViewModel
Grid.UpdateData(); // Call command on ViewModel
}
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));
try this...