I’m trying out the Silverlight 4 beta DataForm control. I don’t seem to be able to get the edit and paging options at the top of the control like I’ve seen in Silverlight 3 examples. Has something changed or am I doing something wrong? Here’s my code:
<UserControl x:Class="SilverlightApplication7.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" xmlns:dataFormToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit">
<Grid x:Name="LayoutRoot" Background="White">
<dataFormToolkit:DataForm HorizontalAlignment="Left" Margin="10" Name="myDataForm" VerticalAlignment="Top" />
</Grid>
</UserControl>
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
Movie movie = new Movie();
myDataForm.CurrentItem = movie;
}
public enum Genres
{
Comedy,
Fantasy,
Drama,
Thriller
}
public class Movie
{
public int MovieID { get; set; }
public string Name { get; set; }
public int Year { get; set; }
public DateTime AddedOn { get; set; }
public string Producer { get; set; }
public Genres Genre { get; set; }
}
}
The behaviour of your code above is identical in VS2008+SL3.
The DataForm only provides the navigation bar if you provide it with a set of items assigned to the ItemsSource property. By assigning directly to the CurrentItem property you are in effect asking the DataForm "please edit this item", which is exactly what its doing.
AnthonyWJones is correct on the paging question. You need to bind to the collection to get the Next/Previous options. I believe you need to implement IEditableObject for the View/Edit option to appear.
Related
This question already has answers here:
Unable to display list items in DataGrid in WPF
(2 answers)
Closed 4 years ago.
I'm new to WPF and MVVM. I'm trying to use a Datagrid along with a Collectionviewsource in my project. I have worked up to some level as below, but my Datagrid is not showing any rows. Below is the code parts. I'm trying to figure what I am missing here. Note that I am only publishing the code parts which are necessary to this problem.
ScanBatchWindow.xaml.cs
public partial class ScanBatchWindow : Window
{
public ScanBatchWindow()
{
InitializeComponent();
ScanBatchViewModel pMV = new ScanBatchViewModel();
this.DataContext = pMV;
}
}
ScanBatchWindow.xaml
<Window x:Class="BatchManPOC.ScanBatchWindow"
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:BatchManPOC"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:cmdBehavior="clr-namespace:BatchManPOC.CmdBehavior"
xmlns:video="clr-namespace:BatchManPOC.Video"
xmlns:Custom="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
mc:Ignorable="d"
Title="ScanBatchWindow"
Height="800"
Width="800">
<Window.Resources>
<CollectionViewSource Source="{Binding p_ListBatches}" x:Key="CVS"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Custom:DataGrid ItemsSource="{Binding Source={StaticResource CVS}}" Margin="8" Grid.Row="0" AutoGenerateColumns="True" IsReadOnly="True">
</Custom:DataGrid>
</Grid>
</Window>
ScanBatchViewModel.cs
Note that I have a BaseViewModel which inherit from INotifyPropertyChanged.
public class ScanBatchViewModel : BaseViewModel
{
public CollectionViewSource CVS { get; set; }
public ObservableCollection<Batch> p_ListBatches { get; set; }
public class Batch
{
public DateTime p_dCreated;
public int p_iReference;
public BatchStatus p_iBatchStatus;
public string p_sFromBranch;
}
/// <summary>
/// Initializes a new instance of the ScanBatchViewModel class.
/// </summary>
public ScanBatchViewModel()
{
LoadBatches();
CVS = new CollectionViewSource();
}
public void LoadBatches()
{
//Add sample objects
p_ListBatches.Add(new Batch() { p_dCreated = DateTime.Now, p_iBatchStatus = BatchStatus.DOC_STATUS_CREATED, p_iReference = 1, p_sFromBranch = "7010888" });
p_ListBatches.Add(new Batch() { p_dCreated = DateTime.Now, p_iBatchStatus = BatchStatus.DOC_STATUS_DELETED, p_iReference = 2, p_sFromBranch = "7010999" });
p_ListBatches.Add(new Batch() { p_dCreated = DateTime.Now, p_iBatchStatus = BatchStatus.DOC_STATUS_RECEIVED, p_iReference = 3, p_sFromBranch = "7010000" });
p_ListBatches.Add(new Batch() { p_dCreated = DateTime.Now, p_iBatchStatus = BatchStatus.DOC_STATUS_SENT, p_iReference = 4, p_sFromBranch = "7010777" });
}
}
Thanks, I found the answer. I have not defined members of the Batch class as properties. Therefore, although we set the values to public members, they will not appear in the .XAML since they are not exposed as properties. Changing them as below worked for me.
public class Batch
{
public DateTime p_dCreated { get; set; }
public int p_iReference { get; set; }
public BatchStatus p_iBatchStatus { get; set; }
public string p_sFromBranch { get; set; }
}
I have a view model which has another class set as its property. The another class contains implementations of ICommand as its properties. I would like to execute one of the commands on a double click.
Unfortunatelly, Caliburn.Micro raises an exception instead ("No target found for method Commands.Command.Execute.").
I've tried to search the net and read the documentation, but without any success.
How to do it correctly?
Note: In real application, the message might be attached to a grid view which might have a different DataContext than the view model containing the commands class.
The XAML:
<Window x:Class="WpfApplication8.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org">
<Grid>
<TextBox
cal:Message.Attach="[Event MouseDoubleClick]
= [Action Commands.Command.Execute(null)]" />
</Grid>
</Window>
The code-behind class:
namespace WpfApplication8
{
public partial class MainWindow
{
public Commands Commands { get; set; }
public MainWindow()
{
this.Commands =
new Commands { Command = new Command { MainWindow = this } };
this.InitializeComponent();
this.DataContext = this;
}
}
public class Commands
{
public Command Command { get; set; }
}
public class Command
{
public MainWindow MainWindow { get; set; }
public void Execute(object parameter)
{
this.MainWindow.Title = "Executed";
}
}
}
As #alik commented, complete solution is:
<Window x:Class="WpfApplication8.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org">
<Grid>
<TextBox
cal:Message.Attach="[Event MouseDoubleClick] = [Action Execute(null)]"
cal:Action.TargetWithoutContext="{Binding Commands.Command}"/>
</Grid>
</Window>
I have maximum simple app. I want to fill listbox when button pressed. I use binding, window DataContext is updated after some operation, but UI not updated!
Here is the code:
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="Button" HorizontalAlignment="Left" Margin="432,288.04,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
<ListBox x:Name="urlsListBox" ItemsSource="{Binding Urls}" HorizontalAlignment="Left" Height="300" Margin="10,10,0,0" VerticalAlignment="Top" Width="417"/>
</Grid>
MainWindow.xaml.cs
namespace WpfApplication1
{
public partial class MainWindow : Window
{
ViewModel model = new ViewModel();
public MainWindow()
{
InitializeComponent();
this.DataContext = model;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
model.GetUrls();
}
}
}
ViewModel.cs
namespace WpfApplication1
{
class ViewModel
{
private ObservableCollection<Url> Urls { get; set; }
public ViewModel()
{
Urls = new ObservableCollection<Url>();
}
public void GetUrls()
{
for (int i = 0; i < 5; i++)
{
Urls.Add(new Url { link = i.ToString() });
}
}
}
public class Url
{
public string link { get; set; }
}
}
Problem stems from the Urls property within the ViewModel class. You need to make Urls public, otherwise the MainWindow cannot access the property:
ViewModel:
namespace WpfApplication1
{
public class ViewModel
{
//make this public otherwise MainWindow will not have access to it!
public ObservableCollection<Url> Urls { get; set; }
public ViewModel()
{
Urls = new ObservableCollection<Url>();
}
public void GetUrls()
{
for (int i = 0; i < 5; i++)
{
Urls.Add(new Url { link = i.ToString() });
}
}
}
public class Url
{
public string link { get; set; }
}
}
Hope this helps and let me know if you have any questions!
You need to support property change notification. Use the NuGet package manager to reference the MVVM Lite project, derive your ViewModel from ViewModelBase and then change your link property to this:
private string _link;
{
public string link
{
get {return this._link;}
set {this._link=value; RaisePropertyChanged(() => this.link); }
}
}
You'll also need to do this for your URLs property which needs to be public in order for binding to work. Also I know this is a little bit outside the scope of the question but in general you shouldn't use the Click handler like this, the "proper" way is to add a RelayCommand to your ViewModel and bind your button's Command property to that.
<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" Height="450" Width="525" Loaded="Window_Loaded">
<Grid>
<DataGrid x:Name="dgrdEmployee" Width="300" Height="300" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"/>
<Button Content="Navigation" x:Name="BtnNavigation" Width="90" Height="40" Margin="204,336,209,-15" />
</Grid>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public class Employees
{
public string Name { get; set; }
public string Id { get; set; }
public string Address { get; set; }
}
public List<Employees> EmployeeList()
{
XDocument employees = XDocument.Load(#"C:\Employees.xml");
List<Employees> employee = (from em in employees.Descendants("Employee")
select new Employees
{
Name = em.Element("Name").Value,
Id = em.Element("Id").Value,
Address = em.Element("Address").Value
}).ToList();
return employee;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
dgrdEmployee.ItemsSource = EmployeeList();
}
}
with above code, i get the following result.
If the data grid scroll viewer is visible the button should be visible, otherwise button should be collapse. Is there any change to do so ?
I tried something like below. But it won't make sense to me.
<Button Content="Navigation" x:Name="BtnNavigation" Visibility="{Binding Visibility, ElementName=dgrdEmployee.ScrollViewer}" Width="90" Height="40" Margin="204,336,209,-15" />
The ScrollViewer is always visible. The ScrollViewer will show or hide its scrollbars depending on how much data is shown.
Assuming that you can get to the VerticalScrollBarVisiblity and HorizontalScrollBarVisiblity properties of the ScrollViewer, you could probably create a MultiBinding between those properties and the button's Visibliity property. You would probably also have to create a value converter, since the scroll bar visibility properties use a different type (that includes an Auto value in addition to the standard visibility values).
I wasn't sure the best way to word the title and couldn't find a related question, but if there is one then kindly direct me to it.
I'm trying to create a tender screen where the number of buttons displayed will be determined by how many types of tenders the user has setup (Cash, Check, Credit, Debit, Gift Card, etc).
So if I had a class like this:
public class TenderType
{
public string DisplayName { get; set; }
// ... other implementation details
}
And on my DataContext I have a TenderTypes collection declared like so:
public ObservableCollection<TenderType> TenderTypes { get; private set; }
Then how might I go about making my view udpate the number of buttons shown depending on how many TenderType instances are in the collection, and bind their Text properties to the DisplayName of the appropriate item in the collection?
You could use an ItemsControl and create a datatemplate for your TenderType to display a Button.
This way it will only show the buttons in your list
Xaml:
<Window x:Class="WpfApplication8.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication8"
Title="MainWindow" Height="105" Width="156" Name="UI">
<Window.Resources>
<DataTemplate DataType="{x:Type local:TenderType}">
<Button Content="{Binding DisplayName}" />
</DataTemplate>
</Window.Resources>
<Grid DataContext="{Binding ElementName=UI}">
<ItemsControl ItemsSource="{Binding TenderTypes}"/>
</Grid>
</Window>
Code:
public partial class MainWindow : Window
{
private ObservableCollection<TenderType> _sourceData = new ObservableCollection<TenderType>();
public MainWindow()
{
InitializeComponent();
TenderTypes.Add(new TenderType { DisplayName = "Stack" });
TenderTypes.Add(new TenderType { DisplayName = "Overflow" });
}
public ObservableCollection<TenderType> TenderTypes
{
get { return _sourceData; }
set { _sourceData = value; }
}
}
public class TenderType
{
public string DisplayName { get; set; }
}
Result: