My ViewModel has a PrintCommand executing a Method called PrintCalendar(). But the Calendar aka datagrid is in the View, so how do I get my datagrid into the ViewModel?
Getting my hands dirty and do all that stuff in code-behind? oh no...
PrintDialog printDlg = new PrintDialog();
printDlg.PrintVisual(datagrid, "Grid Printing.");
You could try this. I have set up a simple demo window with a datagrid, a buttom and a ViewModel. The ViewModel contains the PrintCommand (a RelayCommand from the MVVM Light Toolkit) which accepts a Visual (the datagrid) as the command parameter. There is no code in the code behind all the work is done via binding.
The Xaml:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:WpfTestApplication.ViewModel"
x:Class="WpfTestApplication.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Window.Resources>
<ResourceDictionary>
<vm:WindowViewModel x:Key="WindowViewModel"/>
</ResourceDictionary>
</Window.Resources>
<Grid x:Name="LayoutRoot" DataContext="{DynamicResource WindowViewModel}">
<DockPanel>
<Button Content="Print" Width="70" DockPanel.Dock="Bottom" HorizontalAlignment="Right"
Command="{Binding PrintCommand, Mode=OneWay}" CommandParameter="{Binding ElementName=dataGrid, Mode=OneWay}" />
<DataGrid x:Name="dataGrid" DataContext="{DynamicResource SampleDataSource}" ItemsSource="{Binding Collection}"/>
</DockPanel>
</Grid>
</Window>
and the ViewModel:
using System.Windows.Controls;
using System.Windows.Media;
using GalaSoft.MvvmLight.Command;
namespace WpfTestApplication.ViewModel
{
public class WindowViewModel
{
/// <summary>
/// Command executed to print an visual component. The component is passed in as a parameter.
/// </summary>
public RelayCommand<Visual> PrintCommand
{
get
{
return new RelayCommand<Visual>( v =>
{
PrintDialog printDlg = new PrintDialog();
printDlg.PrintVisual( v, "Grid Printing." );
} );
}
}
}
}
I guess we need the following to be able to show the print dialog box as well:
public RelayCommand<Visual> PrintCommand
{
get
{
return new RelayCommand<Visual>( v =>
{
PrintDialog printDlg = new PrintDialog();
if (Convert.ToBoolean(myPrintDialog.ShowDialog()))
{
printDlg.PrintVisual( v, "Grid Printing." );
}
});
}
}
Related
I have a mvvm app with 22 textboxes.
In my "normal" wpf app I could make a list and then change settings to all the boxes likes this:
Brush MyBrush = Brushes.LightGray;
foreach (var a in AllBoxes)
{
a.Background = MyBrush;
a.IsReadOnly = true;
a.IsTabStop = false;
}
So in mvvm I need to make 3 bindings per textbox and create properties like:
private Brush _clr2;
public Brush Clr2
{
get { return _clr2; }
set
{
_clr2 = value;
NotifyOfPropertyChange(() => Clr2);
}
}
Is there an easier way to do this and not make 66 properties?
You create an UserControl for one TextBox with all bindings...with the ViewModel associated
<StackPanel>
<TextBox .... />
</StackPanel>
Then you use ObservableCollection of your ViewModel and Create a ParentView with ItemControl:
<ItemsControl ItemsSource="{Binding ListOfTextBox}">
And create an itemstemplate for the items in your ItemsControl
<DataTemplate>
<ContentControl cal:View.Model="{Binding}" />
</DataTemplate>
I am using syncfusion datagrid in my xamarin.forms application. I used 2 picker in 2 columns of sfdatagrid.
how can I set selectedindex = 0 of 2nd picker on selectedindexchanged event of 1st picker.as Icoudnt find its refence in my event.pls help.
You can achieve your requirement by binding CLR property with int type to Picker.SelectedIndex property for both Picker, like in the below code example.
C#:
Model:
private int selectedindex;
public int Selectedindex
{
get
{
return selectedindex;
}
set
{
selectedindex = value;
RaisePropertyChanged("Selectedindex");
}
}
XAML
<sfgrid:GridTemplateColumn MappingName="Picker1" >
<sfgrid:GridTemplateColumn.CellTemplate>
<DataTemplate>
<Picker TextColor="Black"
SelectedIndex="{Binding Selectedindex, Mode=TwoWay}" >
<Picker.Items>
<x:String>1</x:String>
<x:String>2</x:String>
</Picker.Items>
</Picker>
</DataTemplate>
</sfgrid:GridTemplateColumn.CellTemplate>
</sfgrid:GridTemplateColumn>
<sfgrid:GridTemplateColumn MappingName="Picker2" >
<sfgrid:GridTemplateColumn.CellTemplate>
<DataTemplate>
<Picker TextColor="Black"
SelectedIndex="{Binding Selectedindex, Mode=TwoWay}" >
<Picker.Items>
<x:String>3</x:String>
<x:String>4</x:String>
</Picker.Items>
</Picker>
</DataTemplate>
</sfgrid:GridTemplateColumn.CellTemplate>
</sfgrid:GridTemplateColumn>
Please refer the below sample for more details:
Sample link: http://www.syncfusion.com/downloads/support/directtrac/169982/ze/XamarinForms1797267025
Regards,
Ashok
So As you can see the ID column should be hidden but its not. And the debugger is showing the value of IDVisible in the xaml file to be "Hidden" but it never makes it to the window. I am calling a property changed method as well. What am I doing wrong, the ID column should disappear or at least that's what I am trying to do.
And here is the code for MainWindowViewModel.cs
namespace MagicDB
{
class MainWindowViewModel : ObservableObject
{
private CardDB _cards;
private Command _InitCardDB;
private Visibility _IDVisible;
public CardDB Cards
{
get { return _cards; }
set { _cards = value; OnPropertyChanged("Cards"); }
}
public Visibility IDVisible
{
get { return _IDVisible; }
set { _IDVisible = value; VerifyPropertyName("IDVisible"); OnPropertyChanged("IDVisible"); }
}
public MainWindowViewModel()
{
IDVisible = Visibility.Hidden;
_InitCardDB = new Command(InitDB, true);
Cards = new CardDB();
}
And the xaml file....
<Window x:Class="WpfDataGrid.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Width="500" Height="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="450*" />
</Grid.RowDefinitions>
<DataGrid AutoGenerateColumns="False"
HorizontalAlignment="Left"
Name="dataGrid1"
VerticalAlignment="Top"
ItemsSource="{Binding Cards.cardDB}"
CanUserReorderColumns="True"
CanUserResizeColumns="True"
CanUserResizeRows="False"
CanUserSortColumns="True"
AlternatingRowBackground="LightBlue"
Width="480" Height="auto" Grid.Row="1" IsSynchronizedWithCurrentItem="True"
>
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding CardID}" Width="25" Visibility="{Binding IDVisible,Mode=TwoWay}"></DataGridTextColumn>
I would check your Visible binding as it is most likely failing. This page explains a few methods that you can use. I personally prefer adjusting the trace level.
I believe the reason that the binding is failing is due to the fact that your DataContext (I assume you have set it somewhere) isn't getting to the DataGrid's columns themselves. This page explains a fix that I have used in the past to solve this problem. I think I originally found that article from this page that has several other good to know WPF 'Gotchas'.
I’m using .Net 4.0 DataGrid with MVVM pattern. I need to enable user to select cells and copy information from selected cells to other DataGrid rows (either via keyboard shortcut or context-menu copy/paste). I tried to achieve this via SelectedItem or sending SelectedItem as CommandParameter but this functions only with the whole row and not with cells.
(DataGrid is bound to ObservableCollection that contains objects with float fields. These fields are then mapped to DataGrid cells)
So, is there any solution in WPF MVVM how to copy DataGrid cells from one row to another?
Thanks in advance
xaml:
<DataGrid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="9" AutoGenerateColumns="False" Height="Auto" HorizontalAlignment="Left"
Name="dataGrid" VerticalAlignment="Top" Width="{Binding ElementName=grid4,Path=Width}"
ScrollViewer.CanContentScroll="False" FrozenColumnCount="1" SelectionUnit="Cell" SelectionMode="Extended" CanUserSortColumns = "False"
CanUserReorderColumns="False" CanUserResizeRows="False" RowHeight="25" RowBackground="LightGray" AlternatingRowBackground="White"
ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Visible"
ItemsSource="{Binding Layers, Mode=TwoWay}" SelectedItem="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Selection, Mode=TwoWay}">
<DataGrid.InputBindings>
<KeyBinding Gesture="Shift" Command="{Binding ItemHandler}" CommandParameter="{Binding ElementName=dataGrid, Path=SelectedItems}"></KeyBinding>
</DataGrid.InputBindings>
ViewModel:
private float _selection = 0.0f;
public float Selection
{
get
{
return _selection;
}
set
{
if (_selection != value)
{
_selection = value;
NotifyPropertyChanged("Selection");
}
}
}
...
public DelegateCommand<IList> SelectionChangedCommand = new DelegateCommand<IList>(
items =>
{
if (items == null)
{
NumberOfItemsSelected = 0;
return;
}
NumberOfItemsSelected = items.Count;
});
public ICommand ItemHandler
{
get
{
return SelectionChangedCommand;
}
}
I think you might be after the SelectionUnit property. Setting this to CellOrRowHeader changes the selection method from full row to a single cell.
You do lose the nice "what row am I on?" highlighting but you are focusing on a single cell. (You could probably extend the datagrid to add your own highlight with the current row logic.)
<DataGrid AutoGenerateColumns="True" Grid.Column="1" Grid.Row="0"
HorizontalAlignment="Stretch" Name="dataGrid" VerticalAlignment="Stretch"
DataContext="{Binding}" ItemsSource="{Binding Path=MyDataTable}"
IsReadOnly="True" SelectionMode="Extended" SelectionUnit="CellOrRowHeader" />
I am a seasoned C and Java programmer, but an absolute WPF newbie.
I am creating a kiosk application that will display a list of images of products that the user will click to see product details and maybe place an order.
I am trying to structure my app with MVVM Foundation because I am used to the benefits of structure and tests.
I wonder what is the most natural way to create a grid of clickable images that will fill the screen left to right, top to bottom (or the other way round, I have no exact requirements).
Any image should be bound to an object that will become current and be displayed in the next screen.
Thanks for your help.
OK! Listen up! Here is how you do that! :)
1) Use ItemsControl together with UniformGrid to get automatic aligment
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid>
</UniformGrid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<Button Width="50" Height="50"/>
<Button Width="50" Height="50"/>
<Button Width="50" Height="50"/>
</ItemsControl>
2) Populate ItemsControl with data from your viewmodel
<ItemsControl ItemsSource="{Binding Path=ImageList}"...
public ObservableCollection<ClickableImage> ImageList
{
get { return m_ImageList;}
}
... constructor
{
m_ImageList = new ObservableCollection<ClickableImage>();
m_ImageList.Add(new ClickableImage("image.png");
}
TADAAAA!
I have refined a little the code. Here is the namespace declaration
xmlns:vm="clr-namespace:TestSandbox.ViewModels"
the DataContext
<UserControl.DataContext>
<vm:ViewModel1/>
</UserControl.DataContext>
and the uniformGrid
<ItemsControl Name="imageList" ItemsSource="{Binding Path=Products}" BorderBrush="#FFA90606" Background="#FFE70F0F">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Margin="50">
</UniformGrid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- The Image binding -->
<Image Source="{Binding Path=image}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
here is the C# code in the view model
public List<Product> Products {get; set; }
public ViewModel1()
{
Products = new List<Product>();
Products.Add(MakeProduct(#"..\images\beemovie.jpg"));
Products.Add(MakeProduct(#"..\images\darkknight.jpg"));
Products.Add(MakeProduct(#"..\images\matrix.jpg"));
Products.Add(MakeProduct(#"..\images\milo.jpg"));
Products.Add(MakeProduct(#"..\images\superhero.jpg"));
Products.Add(MakeProduct(#"..\images\twilight.jpg"));
Products.Add(MakeProduct(#"..\images\xfiles.jpg"));
}
public Product MakeProduct(string path)
{
return new Product(path, MakeImage(path));
}
public BitmapImage MakeImage(string path)
{
BitmapImage bmpi = new BitmapImage();
bmpi.BeginInit();
bmpi.UriSource = new Uri(path, UriKind.Relative);
bmpi.EndInit();
return bmpi;
}
In ViewModel add ObservableList<ClickableImage> m_Images as public property.
In XAML use ListView for displaying ClickableImage.
Create datatemplate for ClickableImage with Image and raised command uppon click.
On the XAML:
<Button Command="{Binding Path=OnClickCommand}"/>
On the ViewModel:
public ICommand OnClickCommand {
get
{
return new RelayCommand(aram => this.Click(), param => this.CanClick);
}
}
public void Click() {
//i was clicked!
globalBigImageViewModel.BigImageContent = m_Image;
}