I tried adding a UserControl to a TabItem in the following way:
<TabControl Margin="1">
<TabItem Header="Control" >
</TabItem>
<TabItem Header="Tray" >
<local:SettingView>
</local:SettingView>
</TabItem>
</TabControl>
It showed in the UI, but bindings appear to be evaluated while the DataContext of the UserControl is still null (Nothing). Why isn't this working?
Related
I have an interaction request pop up and inside that pop up, I have few controls like time picker, radcombobox and so on. I want change events of these controls hit in my view model class using prism commands.
my sample code is not working, time picket value change is not hitting on OnReasonTimeChanged Method.
XAML file
<i:Interaction.Triggers>
<i:EventTrigger SourceName=" " EventName="ValueChanged">
<i:InvokeCommandAction Command="{Binding ReasonTimeChanged}" />
</i:EventTrigger>
<prism:InteractionRequestTrigger SourceObject="{Binding SummaryConfirmationInteractionRequest}">
<prism:PopupChildWindowAction>
<prism:PopupChildWindowAction.ContentTemplate>
<DataTemplate>
<StackPanel Width="Auto" ScrollViewer.VerticalScrollBarVisibility="Hidden" Height="Auto"
MaxHeight="400" >
<ScrollViewer BorderThickness="1" VerticalScrollBarVisibility="Auto" Width="820" Height="Auto" MaxHeight="200">
<StackPanel Height="Auto" >
<controls:XRadGridView x:Name="UnitsGrid" ItemsSource="{Binding Units, Mode=OneWay}"
ScrollViewer.VerticalScrollBarVisibility="Auto"
MaxHeight="300"
IsReadOnly="True"
RowIndicatorVisibility="Collapsed"
CanUserInsertRows="False"
CanUserDeleteRows="False"
ShowColumnHeaders="False"
ShowGroupPanel="False"
CanUserResizeColumns="False"
CanUserReorderColumns="False"
AutoGenerateColumns="False">
<controls:XRadGridView.Columns>
<telerik:GridViewDataColumn Header="DUID"
DataMemberBinding="{Binding DisplayDuid}"
IsReadOnly="True"
Width="Auto" />
<telerik:GridViewDataColumn Header="ReasonTime">
<telerik:GridViewDataColumn.CellTemplate>
<DataTemplate>
<toolkit:TimePicker x:Name="ReasonTime"
VerticalAlignment="Center" HorizontalAlignment="Center" Width="20"
MaxWidth="20"
Loaded="ReasonTime_Loaded"
Format="HHmm"
Value="{Binding OfferHeader.ReasonTime, Mode=TwoWay}"
controls:TimePickerExtensions.UpdateBindingOnValueChanged="{Binding ApplyReasonToAll}"
TabIndex="0"/>
</DataTemplate>
</telerik:GridViewDataColumn.CellTemplate>
</telerik:GridViewDataColumn>
</controls:XRadGridView.Columns>
</controls:XRadGridView>
ViewModel code
Inside constructor I have below code
_reasonTimeChangedCommand = new DelegateCommand(OnReasonTimeChanged);
command details
private readonly DelegateCommand _reasonTimeChangedCommand;
public ICommand ReasonTimeChanged => _reasonTimeChangedCommand;
public void OnReasonTimeChanged()
{
}
The InvokeCommandAction should be inside the popup, to be used within the popup... but you bind to the value to a property (ReasonTime), and that property should be responsible for notifying the change. That's the view model's job, not just being a container for commands or forwarding properties from some DTO.
Most posts regarding DataGrid AutoGenerateColumns seem to deal with how to circumvent default behavior. Unfortunately the default is what I am struggling with.
I have several database tables created with Entity Framework 6.0, and would like to display them in my View using one and the same Datagrid for all tables, and AutoGenerating the Columns. Desired outcome: for the class-specific Viewmodel bound at run-time, display the columns with headers and at least one row.
XAML of the View's user control:
<UserControl.Resources>
<DataTemplate x:Key="TableDataTemplate">
<DataGrid
AutoGenerateColumns="True"
GridLinesVisibility="All"
HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible">
</DataGrid>
</DataTemplate>
</UserControl.Resources>
<StackPanel Height="720" Width="980">
<!-- shows user which menu item was chosen -->
<TextBlock Text="{Binding DisplayName}"/>
<!-- defines the Input data grid for adding to DB table -->
<Grid Height="80" MaxHeight="200">
<ItemsControl
ItemsSource="{Binding CurrentDataTable}"
ItemTemplate="{StaticResource TableDataTemplate}">
</ItemsControl>
</Grid>
The user control is bound to a class-specific 'Class'TableViewModel, implemented for all Database Tables. One example:
class ClientsAdminTableViewModel : TableViewModel
{
// the Property the view binds to
private IList<Client> currentDataTable;
public ObservableCollection<Client> CurrentDataTable
{
get { return CollectionExtensions.ToObservableCollection<Client>(currentDataTable); }
set { currentDataTable = value; OnPropertyChanged("CurrentDataTable")}
}
public ClientsAdminTableViewModel()
{
DisplayName = Strings.ClientAdminDisplayName;
currentDataTable = context.Clients.ToList<Client>();
}
When bound to {Binding CurrentDataTable} this code produces a UI, where I can see a grey body (probably the rows) surrounded by horizontal and vertical scrollbars, on top of which one long line (which must be the header line), but no columns.
Any help is appreciated.
your datagrid needs to have its itemsource set
try adding
ItemsSource="{Binding CurrentDataTable}"
to the datagrid declaration. Also, do you get any binding errors in the output window?
This code now works (Thank you J. King!) The trick was to get rid of the data template, create the data grid right in the grid with the exact same binding statements.
<StackPanel Height="720" Width="980">
<!-- shows user which menu item was chosen -->
<TextBlock Text="{Binding DisplayName}"/>
<!-- defines the Input data grid for adding to DB table -->
<Grid Height="200" MaxHeight="400">
<DataGrid
ItemsSource="{Binding CurrentDataTableNew}"
AutoGenerateColumns="True"
GridLinesVisibility="All"
HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible" >
</DataGrid>
</Grid>
</userControl>
New to SilverLight and to posting here. Please have mercy and be specific :)
Using RIA services with DomainDataSource and DataGrid control to display data rows from SQL server query
Goal: Have checkbox column (UI only - not a data field) to allow user to select multiple records/rows
BackGround:
1) Created new SilverLight 4, C# solution with RIA services
2) in ProjectName.Web
Created Entity Framework (EF) model referencing SQL server table/view (built solution).
Created Domain Sevice using EF model (built solution).
3) in SilverLightProjectName
From Data Sources window, dragged table onto a design surface to create DomainDataSource and DataGrid (this works great to bind DataGrid to data source)
4) in MainPage.XAML added checkbox column
What's Happening: checkboxes are selected/checked by user, scroll down, scroll back up, all checkboxes reset and ONLY Datagrid.SelectedItem is still checked. I have read this behavior is 'by design' due to paging.
<sdk:DataGrid RowStyle="{StaticResource newDataGridStyle}" AutoGenerateColumns="False" ItemsSource="{Binding ElementName=ddsPagerApp, Path=Data}" Name="vwPagerAppDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected" MouseLeftButtonDown="vwPagerAppDataGrid_MouseLeftButtonDown" VerticalGridLinesBrush="#FFB9B9B9" FontSize="10" Grid.Row="3" SelectionChanged="vwPagerAppDataGrid_SelectionChanged" KeyDown="vwPagerAppDataGrid_KeyDown" MouseLeftButtonUp="vwPagerAppDataGrid_MouseLeftButtonUp" MouseRightButtonUp="vwPagerAppDataGrid_MouseRightButtonUp" DataContext="{Binding}" SelectionMode="Single" IsEnabled="True" IsReadOnly="False" TabIndex="2" Grid.Column="1" Margin="0,10,9,9">
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn IsReadOnly="False">
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<CheckBox Name="ChkSelected" IsThreeState="False" IsChecked="{Binding Path=IsChecked, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Center" Unchecked="IndividualCheckBox_Unchecked" Checked="IndividualCheckBox_Checked" Width="Auto" Height="Auto" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTextColumn x:Name="fullNameColumn" Binding="{Binding Path=FullName}" Header="Full Name" IsReadOnly="True" />
<sdk:DataGridTextColumn x:Name="departmentColumn" Binding="{Binding Path=department}" Header="Department" IsReadOnly="True" />
<sdk:DataGridTextColumn x:Name="pager_number_displayColumn" Binding="{Binding Path=pager_number_display}" Header="Pager Number" IsReadOnly="True" />
<sdk:DataGridTextColumn x:Name="PageTo" Binding="{Binding Path=PageTo}" Header="Page To" IsReadOnly="True" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
<riaControls:DomainDataSource AutoLoad="True" d:DesignData="{d:DesignInstance my:vwPagerApp, CreateList=true}" Height="0" LoadedData="ddsPagerApp_LoadedData" Name="ddsPagerApp" QueryName="GetVwPagerAppsQuery" Width="0" Margin="10,0,25,45" Background="#FF7D0000" Foreground="#FF7D0000" Visibility="Visible">
<riaControls:DomainDataSource.DomainContext>
<my:NotifyDomainContext />
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
Attempt 1:
in EFModel.edmx, added Boolean Scalar Property 'IsChecked'
in DomainService.metadata.cs, added public bool IsChecked { get; set; }
in MainPage.XAML. added (above) IsChecked="{Binding Path=IsChecked, Mode=TwoWay}"
Getting error: Error 11009: Property ' ' is not mapped
UPDATE: Reversed Attempt 1:
Attempt 2:
Researching possibility of defining a partial class for the entity, wiring to DataGrid, and using that to track CheckBox values. Any advice on if this will work/how to?
Trying my best to absorb this. Please enlighten me...and thank you in advance :)
This is what I implemented and it worked beautifully. I hope it helps someone else in the future :)
1) SilverLight Project C#: Extend entity class using partial class (in separate file, but within same namespace – compiles into 1 class but keeps generated code separate)
namespace Pager.Web
{
public partial class pager_grp
{
bool _IsChecked = false;
public bool IsChecked
{
get
{return this._IsChecked;}
set
{this._IsChecked = !IsChecked;}
}
}
}
2) SilverLight Project GUI: Create Column in DataGrid of type DataGridTemplateColumn named chkSelected
3) SilverLight Project XAML: use template and bind to new property declared in partial class
<sdk:DataGridTemplateColumn IsReadOnly="False">
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<CheckBox Name="ChkSelected" IsThreeState="False" IsChecked="{Binding Path=IsChecked, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Center" Unchecked="IndividualCheckBox_Unchecked" Checked="IndividualCheckBox_Checked" Width="Auto" Height="Auto" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
I have a Silverlight 4 app created in MVVMLight.
In a view I have a DataGrid that is bound to my ViewModel, which has SeletedItem bound to SelectedItem again in my ViwModel :
<sdk:DataGrid Name="MyGrid" AutoGenerateColumns="False" Grid.Row="3" MaxHeight="200" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" RowHeight="35"
SelectedItem="{Binding SelectedItem, Mode=TwoWay, ValidatesOnNotifyDataErrors=False}" ItemsSource="{Binding Items}" >
This all works just as it should as in when I click on an item in the grid the SelectedItem in my ViewModel is set correctly.
Now I have added a button to the rows in the Datagrid and added an EventToCommand to the button which is bound to the same ViewModel:
<Button Content="Update" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<Command:EventToCommand Command="{Binding Source={StaticResource Locator}, Path=MainDialog.ButtonCommand, Mode=TwoWay}" />
</i:EventTrigger>
</i:Interaction.Triggers>
This command fires and works correctly The Problem Is the SelectedItem property that was set earlier, that I now want to use is set to null!!
Why is this EventToCommand resetting the SelecteedItem property and how do I stop it so I can use it???
you should shar your code to let us see what the problem is. But maybe problem is that you set selected item as object that isn't in your itemsource collection of datagrid. Try to set selecteditem like this
SelectedItem = Items.Where(x => x.Id == someId).First();
And see if this is the problem.. Ofcourse change condition in Where.. :)
In my scenario I have a MainView + MainViewModel, UserControl1 + UserControl 2.
In the MainView I have 2 buttons labeled: Button_ShowUserControl1 + Button_ShowUserControl2.
At the lower part of the MainView I have a "ContentGrid" which takes/should_take... every UserControl.
My goal:
When Button_ShowUserControl1 is clicked UserControl1 is Visible and UserControl2 OR any other UserControl must be set to Collapsed. Same is valid for Button_ShowUserControl2.
My problem:
1.) As the UserControls shall be loaded at application start how can I put them all together in the one "ContentGrid"? Thats actually not possible... so how can I make one UserControl visible while the other is in the same place/"ContentGrid" just collapsed ?
2.) As 1.) seems not possible how can I instantiate all UserControls at start of the application and make them only Visible/Collapsed when respective Button is clicked?
3.) As a UserControl has a property Visibility = Visible/Hidden/Collapsed, how can I bind to a property in a ViewModel return such a value like Collapsed? I only could get a boolean value like Visibility = false/true ?
My testcode:
<Grid x:Name="LayoutRoot" Background="#FFBDF5BD" ShowGridLines="False">
<Grid.RowDefinitions>
<RowDefinition Height="96*" />
<RowDefinition Height="289*" />
</Grid.RowDefinitions>
<Grid HorizontalAlignment="Stretch" Name="MenuGrid" VerticalAlignment="Stretch" Background="#FFCECEFF">
<StackPanel Name="stackPanel1" Background="#FFEDFF00" Orientation="Horizontal">
<Button Content="User Data 1" Height="35" Name="button1" Command="{Binding Path=ShowUserControl1Command}" Width="150" Margin="100,0,0,0" />
<Button Content="User Data 2" Height="35" Name="button2" Width="150" Margin="100,0,0,0" />
</StackPanel>
</Grid>
<Grid Grid.Row="1" HorizontalAlignment="Stretch" Name="ContentGrid" VerticalAlignment="Stretch" Background="#FFB15454" />
</Grid>
<UserControl x:Class="SwapUserControls.MVVM.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:vm="clr-namespace:SwapUserControls.MVVM.ViewModel"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" Visibility="{Binding IsUserControl1Collapsed, Path=Value}">
<UserControl.Resources>
<vm:MainViewModel x:Key="MainViewModelID" />
</UserControl.Resources>
<UserControl.DataContext>
<Binding Source="{StaticResource MainViewModelID}" />
</UserControl.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="228*" />
<RowDefinition Height="72*" />
</Grid.RowDefinitions>
<Button Content="UserControl2" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="112,27,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
<DataGrid HorizontalAlignment="Stretch" Name="dataGrid1" VerticalAlignment="Stretch" Background="#FFC046F8" />
</Grid>
public class MainViewModel : ViewModelBase
{
RelayCommand _ShowUserControl1Command;
private bool _IsUserControl1Collapsed;
public RelayCommand ShowUserControl1Command
{
get
{
if (_ShowUserControl1Command == null)
{
_ShowUserControl1Command = new RelayCommand( () => ShowUserControl1() );
}
return _ShowUserControl1Command;
}
}
public void ShowUserControl1()
{
_IsUserControl1Collapsed = true;
}
public bool IsUserControl1Collapsed
{
get
{
return _IsUserControl1Collapsed;
}
}
}
Yes the code is wrong, therefore I ask here :)
You only have 2 things wrong with this code.
1) You can't set the visibility of a usercontrol directly... you have to set it on a container:
<Grid Visibility="Collapsed">
<myControls:MyUserControl />
</Grid>
2) Visibility is not a boolean value, it is an enum. As such, you will need to use a converter to convert from boolean to Visibility. Observe:
<Window ...>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis" />
</Window.Resources>
<Grid Visibility="{Binding ShouldShowUsercontrol1, Converter={StaticResource BoolToVis}}">
<myControls:MyUserControl />
</Grid>
</Window>
That should be it. Hope this helps.
There are other things that you are leaving clues about that might affect the ability of this to work. For example, you don't show the biggest container element... are you wrapping everything in a StackPanel? If you are wrapping everything in a Grid, for example, the controls will overlay everything in layers.
Try these changes I suggest... it should get you closer.
Edit: Another idea using data templates
Another thing you could do is make sure you have a unique ViewModel for each of these views you want to show and hide:
public class MyFirstViewModel : ViewModel
{
}
public class MySecondViewModel : ViewModel
{
}
Then from your "parent" or "main" ViewModel, you show or hide the views you want by virtue of having them in a collection of ViewModels:
public MyMainViewModel : ViewModel
{
public ObservableCollection<ViewModel> ViewsToShow
{
...
}
public void ShowFirstViewModel()
{
ViewsToShow.Add(new MyFirstViewModel());
}
}
To wire everything up in your view, you would then datatemplate these types with their user controls (but this would not cause those views to be instantiated unless they were needed:
<Window ...>
<Window.Resources>
<DataTemplate DataType="{x:Type myViewModels:MyFirstViewModel}">
<myViews:MyFirstView />
</DataTemplate>
<DataTemplate DataType="{x:Type myViewModels:MySecondViewModel}">
<myViews:MySecondView />
</DataTemplate>
</Window.Resources>
<ItemsControl ItemsSource="{Binding ViewsToShow}" />
</Window>
And for any ViewModels you put in "ViewsToShow", the view will automatically see that and template in the appropriate view. Again, without instantiating it before it's needed.
This is probably a little cleaner than putting everything single thing in the View and setting visibility, but it would be dependent on you have a unique view model type for every view, which might not be the case.
The question of saving state comes up when using the DataTemplated approach. The solution here is to tread your ViewModel as the state of the control and design both your ViewModels and your Views accordingly. Here is an example that allows you to swap out your Views using DataTemplating, but switching back and forth saves state.
Assume you have the setup from the last section w/ 2 viewmodels that have datatemplates defined. Let's change up the MainViewModel a little:
public MyMainViewModel : ViewModel
{
public RelayCommand SwapViewsCommand
{
...
}
public ViewModel View
{
...
}
private ViewModel _hiddenView;
public MyMainViewModel()
{
View = new MyFirstViewModel();
_hiddenView = new MySecondViewModel();
SwapViewsCommand = new RelayCommand(SwapViewModels);
}
public void SwapViewModels()
{
var hidden = _hiddenView;
_hiddenView = View;
View = hidden;
}
}
And a few changes to the main view. I've omitted the DataTemplates for brevity.
<Window ...>
<!-- DataTemplates Here -->
<Button Command="{Binding SwapViewsCommand}">Swap!</Button>
<ContentControl Content="{Binding View}" />
</Window>
That's it. The secret here is I'm saving the reference to the original view model. This way, let's say there is a string property in a viewmodel and an associated textbox in the DataTemplated usercontrol with a two-way binding then the state will essentially be saved.