Programmatically replace GridView cell contents on load - wpf

I am working on a program in WPF for the first time. I have a ListView in GridView mode displaying data from a bound dataset (which is grabbed from a database).
In my database, "date of birth" is not a required field. As such, any record without a dob had the value set to DateTime.MinValue. On each of these minimum value dates, the date shows in the cell as 01/01/0001. I am trying to find a way to either format the cell so that DateTime.MinValue doesn't show, or replace each MinValue with "".
My thought was to either use the "Loaded" event of the textblock the date is in and replace each instance of "01/01/0001", or loop through the dataset before sending it to the GridView and remove/replace them there. I've not had any luck figuring out how to do either.
My xaml code for the GridView is:
<Grid>
<ListView x:Name="resultsListView" GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler" Margin="0,54,0,28" ItemsSource="{Binding Path=Table}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Path=LastName}"
Header="Last Name"
Width="150"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=FirstName}"
Header="First Name"
Width="100"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=MiddleName}"
Header="Middle Name"
Width="100"/>
<GridViewColumn Header="Date of Birth" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock TextAlignment="Justify" Text="{Binding Path=DateOfBirth, StringFormat='{}{0:MM/dd/yyyy}'}" Loaded="TextBlock_Loaded" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
Code for the DataSet:
private void FillListView(DataSet ds)
{
if (resultsListView.Items.Count != 0)
{
resultsListView.Items.Clear();
}
resultsListView.DataContext = ds.Tables[0].DefaultView;
}
Any advice on how to show blanks for DateTime.MinValue in my GridView would be much appreciated!

I would make an IValueConverter that deals with this, and include it in your binding expression.
In your resources:
<local:DateTimeConverter x:Key="DateTimeConverter" />
Then update your binding:
<TextBlock Text="{Binding Path=DateOfBirth,
Converter={StaticResource DateTimeConverter},
ConverterParameter='MM/dd/yyyy'}" />
Then define the class:
public class DateTimeConverter : IValueConverter
This has two methods. You need only to implement Convert (unless you're planning on using two-way binding). In this method, you can take the format string via a paramater (as I've passed in the binding expression above) and also check for DateTime.MinValue and return a blank string.

Related

How to enable a cell in a disabled row of a WPF ListView

I have a WPF ListView who's view is set to a GridView. Rows in the list are sometimes disabled but I need one column of cells to ALWAYS be enabled. We are displaying a link in the "URL" column and the user needs the ability to click the link even if the row is disabled. Currently, if the row is disabled, the link is disabled as well.
I currently have this in XAML:
<ListView.View>
<GridView>
<GridViewColumn Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock
Text="{Binding Item.Name}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Description">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock
Text="{Binding Item.Description}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="URL">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Label>
<Hyperlink
Command="{Binding ViewModel.OpenInstructionsCommand}">
<TextBlock Text="View" />
</Hyperlink>
</Label>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
Although it is not guaranteed to work without side effects for all control types, it is possible to extend the control that you want to remain enabled to ignore the propagation of the IsEnabled property from the parent control. For an example of this with a bit more explanation, see Cedric Dussud's post here.
In this case, your code might look like:
internal class EnabledHyperlink : Hyperlink
{
static EnabledHyperlink()
{
IsEnabledProperty.OverrideMetadata(typeof (EnabledHyperlink),
new UIPropertyMetadata(true,
IsEnabledPropertyChanged,
CoerceIsEnabled));
}
private static void IsEnabledPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
{
}
private static object CoerceIsEnabled(DependencyObject source, object value)
{
return value;
}
}

Binding GrivdViewColumn's Width Property in XAML or in Code?

I would like to bind GrivdViewColumn's Width Property with my ViewModel. Lets say an instance of ViewModel is the Datacontext of the Window. ViewModel has got Properties called IdWidth, LastNameWidth, FirstNameWidth. And that Window contains the following given ListVeiw in a stackPanel. Everything is fine but somehow the Width Property of GridViewColumn is not bound. Please post the code after making sure that it works.
<ListView Name="PatientListView"
ItemsSource="{Binding Patients}"
SelectionMode="Single">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Patient-Id"
Width="{Binding IdWidth, Mode=TwoWay}"
DisplayMemberBinding="{Binding PatientId}"/>
<GridViewColumn Header="Last Name"
Width="{Binding LastNameWidth, Mode=TwoWay}"
DisplayMemberBinding="{Binding LastName}"/>
<GridViewColumn Header="Last Name"
Width="{Binding FirstNameWidth, Mode=TwoWay}"
DisplayMemberBinding="{Binding FirstName}" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
The accepted answer is wrong as outlined in my comment, looking at your paths you seem to expect the DataContext to be the item, which cannot work (there are multiple items to begin with, which should be chosen?).
The DataContext of the columns is the DataContext of the ListView.
This example will result in a column with the Header Lorem Ipsum:
<ListView>
<ListView.DataContext>
<Label Content="Lorem Ipsum"/>
</ListView.DataContext>
<ListView.View>
<GridView>
<GridViewColumn Header="{Binding Content}"/>
</GridView>
</ListView.View>
</ListView>
Also you might be interested in this article on debugging databindings.
Edit: FrameworkElement is not required for DataBinding, sorry for this incorrect interpretation of the citation from MSDN below.
See comments and #H.B. 's answer
GridViewColumn does not inherit from FrameworkElement, which is required for databinding.
see MSDN:
Support for data binding and dynamic resource references: [...], but the ability to resolve a member value that is stored as an Expression (the programming construct that underlies both data binding and dynamic resources) is implemented by FrameworkElement

WPF Listview flickering problem

I am using a thread for reading the file and make a array of objects from the data read.A seperate thread for filtering records based on some filters is being used.
I am using listview to show data for dataset I get as per above.
While laoding a file everthing seems good but when I search,the problem exists.
while searching when I apply filters for the 1st time, everything is okay. Now again when I apply filters, data of the previous search is show for 1 sec(kind of flicker) and then the new data according to current filter is rendered.
I am using dispatcher for updating UI.
Before I bind any data, I try to clear ListView ItemSource by setting it to null
XAML code i am using is :
{
<ListView Name="listView1"
Grid.Row="0"
ItemsSource= "{Binding ElementName=Window1, Path=Entries}"
AllowDrop="True"
SelectionChanged="listView1_SelectionChanged"
Drop="listView1_Drop">
<ListView.View>
<GridView x:Name="GridView1" >
<GridViewColumn Header="Item" DisplayMemberBinding="{Binding Item}" />
<GridViewColumn Header="TimeStamp" DisplayMemberBinding="{Binding TimeStamp}"/>
<GridViewColumn Header="">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Image}" Width="16" Height="16" VerticalAlignment="Top" HorizontalAlignment="Left"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Level" DisplayMemberBinding="{Binding Level}"/>
<GridViewColumn Header="Class" DisplayMemberBinding="{Binding Class}"/>
<GridViewColumn Header="Message" DisplayMemberBinding="{Binding Message1}" Width="250" />
</GridView>
</ListView.View>
</ListView>
}
Code Behind is :
private void ClearListView()
{
UpdateList update = new UpdateList(UpdateListData);
List<LogEntry> searcheddata = new List<LogEntry>();
searcheddata = null;
listView1.ItemsSource = null;
listView1.Items.Clear();
listView1.Items.Refresh();
pdDispatcher.BeginInvoke(update, DispatcherPriority.Render, searcheddata);
}
psdispatcher is the dispatcher used to update the UI & searchdata is function to assign datasource to listview

How to set property only on second column of a ListView?

Introduction
I have a ListView and want to format only the second column. The following XAML code does that:
<ListView x:Name="listview">
<ListView.View>
<GridView>
<GridViewColumn Header="Property" DisplayMemberBinding="{Binding Path=Key}" Width="100"/>
<!-- <GridViewColumn Header="Value" DisplayMemberBinding="{Binding Path=Value}" Width="250">-->
<GridViewColumn Header="Value" Width="250">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Value}" Foreground="CornflowerBlue" AutomationProperties.Name="{Binding Path=Key}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
The one problem I have is that the AutomationProperties.Name property is not being set. I was checking it with the Coded UI Test Builder and the property is empty. The Text and the Foreground property are being set correctly.
Question
Does anyone know why AutomationProperties.Name is not being set?
Additional information
Strangly enough, the following XAML code does set the AutomationProperties.Name
<ListView x:Name="listview">
<ListView.Resources>
<Style TargetType="TextBlock">
<Setter Property="AutomationProperties.Name" Value="{Binding Key}"/>
</Style>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn Header="Property" DisplayMemberBinding="{Binding Path=Key}" Width="100"/>
<GridViewColumn Header="Value" DisplayMemberBinding="{Binding Path=Value}" Width="250"/>
</GridView>
</ListView.View>
</ListView>
The problem here though is that AutomationProperties.Name is being set on all the columns. But I only want it on the second one because otherwise my Coded UI Test code returns the wrong value (that of the first column, instead of that of the second column which I want).
Don't know if you're aware of this, but a very helpful tool in analyzing these types of problems is Snoop.
In particular, it will highlight (with red) any data binding errors you may have.
I took a look myself and it sure seems as if the first piece of xaml (above) is now working (after you cleared up the syntax error). In Snoop, bound properties are highlighted with a light green.
Here is a screen shot of Snoop showing the property is being set correctly:
And here is a screen shot of Snoop showing the TextBlock (where the property isn't set ... no light green column) on the first column:
And, finally, I've intentionally broken the binding to show you what Snoop shows when something is wrong and you have a data binding error (it is highlighted in red and one of the columns gives you additional information):

WPF: How do I apply custom formatting to a ListView?

My ListView is petty simple:
<ListView ItemsSource="{Binding Path=ActiveCounters}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=Name}" />
<GridViewColumn Header="Value" DisplayMemberBinding="{Binding Path=Value}" />
<GridViewColumn Header="As Of Date" DisplayMemberBinding="{Binding Path=AsOfDate}" />
<GridViewColumn Header="Duration" DisplayMemberBinding="{Binding Path=Duration}" />
<GridViewColumn Header="Last Modified Date" DisplayMemberBinding="{Binding Path=Timestamp}" />
</GridView>
</ListView.View>
</ListView>
What I want to do is:
Format "Value" using the built-in format "D0"
Format "AsOfDate" and "Last Modified Date" using the custom string "MMM d hh:mm:ss tt"
Format "Duration" with a function defined as "String DurationString(TimeSpan)
For Value and AsOfDate columns use StringFormat attribute - a new feature of WPF 3.5 SP1.
More about it here:
http://blogs.msdn.com/llobo/archive/2008/05/19/wpf-3-5-sp1-feature-stringformat.aspx
http://elegantcode.com/2009/04/07/wpf-stringformat-in-xaml-with-the-stringformat-attribute/
If you want to call a custom function on a bound value, then implement a value converter for that.
http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx
You can call your custom function from convert method.
StringFormat can be added to your binding statement. For example
<GridViewColumn
Header="As Of Date"
DisplayMemberBinding="{Binding Path=AsOfDate, StringFormat={}{0:MMM d hh:mm:ss tt}}" />
See this post for more usage examples

Resources