I am dynamically loading a xaml file into my program that has a binding:
<ListView
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Grid.Row="2" BorderBrush="White" Name="ListView1"
ItemsSource="{Binding Path=line}" HorizontalAlignment="Stretch">
<ListView.View>
<GridView>
<GridViewColumn Header="Lines"
DisplayMemberBinding="{Binding Path=aline}" />
</GridView>
</ListView.View>
</ListView >
In my program, I want to check if the Binding exists.
How should this be achieved?
Edit: The aline is a property of the DataContext object
You can check for bindings like this:
BindingExpression be = BindingOperations.GetBindingExpression(ListView1, ItemsSourceProperty);
return be != null ? "ItemsSource is bound" : "ItemsSource is not bound";
if (ListView1.ItemsSource != null)
Console.WriteLine("Is Bound");
else Console.WriteLine("Is Not bound");
Related
I have a 2 column ListView and I'm trying to fill it using and IDictionary with the following code.
System.Collections.IDictionary entryList = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User);
foreach (System.Collections.DictionaryEntry de in entryList)
{
Row row = new Row();
row.Name1 = (string)de.Key;
row.Name2 = (string)de.Value;
this.list1.Items.Add(row);
}
public class Row
{
public string Name1 { get; set; }
public string Name2 { get; set; }
}
XAML:
<ListView x:Name="varList"
Grid.ColumnSpan="1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Height="400"
Width="500"
Margin="0, 30, 0, 0">
<ListView.View>
<GridView>
<GridViewColumn Width="150" Header="Name" />
<GridViewColumn Width="350" Header="Path" />
</GridView>
</ListView.View>
</ListView>
But every row and column gets filled with "Project.Views.Row".
Anyone got any idea on how to fix it? Thank you very much.
A ListView (and every other control for that matter) will display the results of calling ToString when given an object to display.
For a standard class, thats its qualified name; Project.Views.Row in your example.
There are two ways to fix this:
Don't add an object. Instead, format the string as you want it ie:
list1.Items.Add(String.Format({0}:{1}, row.Name1, row.Name2));
Do this the right way and use MVVM. In this case your XAML needs a data template:
<ListView ItemsSource="{Binding Rows}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name1}"/>
<TextBlock Text="{Binding Name2}"/>
</StackPanel>
</DataTemplate>
<ListView.ItemTemplate>
</ListView>
For a grid view:
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name1}" />
<GridViewColumn Header="Path" DisplayMemberBinding="{Binding Name2}"/>
</GridView>
</ListView.View>
Binding the ItemsSource is not actually necessary, but since we are doing everything the right way, you should do it so you are not directly manipulating the UI from code.
I have this setup for my ListView and I am trying to make Binding to work in my MVVM structure.
This is the xaml code:
<Window.Resources>
<CollectionViewSource
x:Key="DeviceList"
Source="{Binding Path=DiscoveredDevicesList}">
</CollectionViewSource>
</Window.Resources>
<ListView
Grid.Row="1"
Width="500"
HorizontalAlignment="Left"
Margin="10"
Grid.Column="1"
DataContext="{StaticResource DeviceList}"
ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Header="Device name" DisplayMemberBinding="{Binding Path=DeviceName}"/>
<GridViewColumn Header="Rssi" DisplayMemberBinding="{Binding Path=Rssi}"/>
<GridViewColumn Header="GPS Row" DisplayMemberBinding="{Binding Path=GpsSignal}"/>
</GridView>
</ListView.View>
</ListView>
And the following is the code to implement the binding
//Constructor
public MainWindowViewModel()
{
DiscoveredDevicesList = new ObservableCollection<MyDeviceInfo>();
}
private ObservableCollection<MyDeviceInfo> _DiscoveredDevicesList;
public ObservableCollection<MyDeviceInfo> DiscoveredDevicesList
{
get
{
return _DiscoveredDevicesList;
}
set
{
_DiscoveredDevicesList = value;
OnPropertyChanged("DiscoveredDevicesList");
}
}
Using Add() and Clear() updates the view just fine when used as below:
var client = new BluetoothClient();
DiscoveredDevicesList.Clear();
IEnumerable<MyDeviceInfo> csaDevices = null;
csaDevices = await DiscoverCsaDevicesAsync(client);
foreach (var csaDevice in csaDevices)
{
DiscoveredDevicesList.Add(csaDevice);
DiscoveredDevicesList.First().GpsSignal = true;
}
So I can see the value of GpsSignal as changed to ture from initial opposite in my view.
However, if I put the following same line in the OnClick of a button doesn't do the same and the value stays false since I am not using any Add() or Clear() and I simply rely on the OnPropertyChanged to do the trick for me.
DiscoveredDevicesList.First().GpsSignal = true;
The rest of the bindings such as button clicks and textblock information work fine, then I would assume it shouldn't be the problem with implementation of the binding on the back of the stage.
Would appreciate your suggestions on this.
if your MyDeviceInfo class implement INotifyPropertyChanged and your property GpsSignal raise OnPropertyChanged() you should see all changes when your bindings are right.
nevertheless i would change your code in this way:
remove CollectionViewSource from your resources and use simple binding
<Window.Resources>
</Window.Resources>
<ListView ItemsSource="{Binding DeviceList}">
<ListView.View>
<GridView>
<GridViewColumn Header="Device name" DisplayMemberBinding="{Binding Path=DeviceName}"/>
<GridViewColumn Header="Rssi" DisplayMemberBinding="{Binding Path=Rssi}"/>
<GridViewColumn Header="GPS Row" DisplayMemberBinding="{Binding Path=GpsSignal}"/>
</GridView>
</ListView.View>
</ListView>
set the datacontext for your window to your MainWindowViewModel in codebehind or xaml.
instead of using OnClick, pls use ICommands (RelayCommand or DelegateCommand)
<Button Command="{Binding MyCommand4GpsSignalIsTrue}" />
I had a listview with validation fine but I wanted to changed the look of the textbox that was inside of listview so I changed it to datagrid. After I changed it the validation got screwed up. Whenever a automatic name is added, I got the error message says the name is already existed even though it is not. Why was it fine with listview? Any input is welcome. Here is the code;
Listview which the validation is fine:
<ListView Name="_regionQueryListBox" Width="122"
HorizontalAlignment="Left" VerticalAlignment="Stretch"
DataContext="{Binding}" IsSynchronizedWithCurrentItem="True"
Style="{StaticResource ListViewRegionSelectorStyle}"
ItemsSource="{Binding Path=Model}">
<ListView.View>
<GridView>
<GridViewColumn Header="Region"
Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox HorizontalAlignment="Left" VerticalAlignment="Stretch"
Text="{Binding Path=RegionName}">
</TextBox>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Datagrid, validation doesn't work:
<DataGrid x:Name="_regionQueryListBox" HorizontalAlignment="Left" VerticalAlignment="Stretch"
AutoGenerateColumns="False"
AlternatingRowBackground="Silver" AlternationCount="2"
CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserSortColumns="False"
CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="False"
VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Disabled"
SelectionMode="Single"
DataContext="{Binding}"
ItemsSource="{Binding Path=Model}" >
<DataGrid.Columns>
<DataGridTemplateColumn Header="Region" Width="110" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=RegionName}"
TextChanged="regionTextBox_TextChanged" >
</TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Validation:
private void regionTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
{
TextBox textBox = sender as TextBox;
if (textBox != null)
{
string name = textBox.Text;
StringBuilder errorMessage = null;
RegionQueryViewModel queryViewModel = DataContext as RegionQueryViewModel;
if (queryViewModel.Model.Any(q => q.RegionName == name))
{
errorMessage = new StringBuilder();
errorMessage.AppendLine(string.Format("{0} already exists in the list.", name));
}
if (errorMessage != null)
{
MessageBox.Show(errorMessage.ToString(), "Item Already Exists");
name = string.Empty;
//RegionName = name;
return;
}
}
}
I'm guessing that the default updatesourcetrigger=lostfocus of the datagrid messes up your validation.
<DataTemplate>
<TextBox Text="{Binding Path=RegionName, UpdateSourceTrigger=PropertyChanged}"
TextChanged="regionTextBox_TextChanged" />
</DataTemplate>
I am dynamically loading a xaml file. This is what the xaml looks like:
<ListView Grid.Row="2" BorderBrush="White"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="ListView1"
ItemsSource="{Binding Path=line}"
HorizontalAlignment="Stretch">
<ListView.View>
<GridView>
<GridViewColumn Header="Lines"
DisplayMemberBinding="{Binding Path=aline}" />
</GridView>
</ListView.View>
</ListView >
The xaml cannot be changed.
You can just change the FontSize in your xaml.
<ListView Grid.Row="2" BorderBrush="White" FontSize="20" .................
However if you are loading your Xaml from a file you will have to load it first then change the FontSize
Example:
using (FileStream stream = new FileStream("c:\\test.xaml", FileMode.Open))
{
var listView = (ListView)XamlReader.Load(stream);
// change font size
listView.FontSize = 20;
// apply listView to whatever you need
}
I'm using a ListView that contains a GridView, there's a gridviewcolumn which only contains buttons. In the buttonclick event, how do I get the position (I just need the row in this case) of the button which fired the event?
<ListView.View>
<GridView>
<GridViewColumn Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Width="Auto" Height="Auto" Background="#00000000" BorderBrush="#00000000" BorderThickness="0" Click="Finalizado_Click">
<Button.Content>
<Image Source="Content/okay.png" Width="8" Height="8"/>
</Button.Content>
</Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
I know the columns are automatically autogeneratedfields, if you change them to buttonfields you might be able to get a little more information. Sorry I can't help more than that.
public ListViewItem GetRow(DependencyObject item)
{
DependencyObject dObj = VisualTreeHelper.GetParent(item);
if (dObj == null)
return null;
if (dObj is ListViewItem)
return dObj as ListViewItem;
return GetRow(dObj);
}