I'm trying to use XAML binding to affect the gridview datatemplate element size from a slider on my screen.
I have a gridview made of thumbnails images where the elements are defined as following:
<GridView.ItemTemplate >
<DataTemplate >
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center"
VerticalAlignment="Center"
KeyDown="IsitenterThumb"
BorderBrush="LightSeaGreen"
BorderThickness="1"
PointerWheelChanged="ctlThumbnails_PointerWheelChanged">
<Image Source="{Binding thumb}"
x:Name="thumbimg"
Visibility="Visible"
Height="{Binding ItemSize}" Width="{Binding ItemSize, ElementName=page}" Stretch="Uniform"
Tapped="ThumbnailSelected"
DoubleTapped="CloseThumbnails"
/>
<TextBlock Text="{Binding name}" Margin="5,5"
Foreground="White"
Width="{Binding ItemSize}"
/>
</StackPanel>
</DataTemplate>
And I have the following variable defined as follow:
public double ItemSize
{
get => _itemSize;
set
{
if (_itemSize != value)
{
_itemSize = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ItemSize)));
}
}
}
private double _itemSize;
public event PropertyChangedEventHandler PropertyChanged;
I would have thought that changing the value of ItemSize would have affected the gridview datatemplate. This is taken litterally from the PhotoLab sample.
Instead I get a single huge "thumbimg" per page... Any help would be greatly appreciated!
Ok... I got it finally. I'm not quite sure what I was doing wrong above, but the code below works.
I have put the DataTemplate as part of a Page.Resource, I'm not sure if this is what was causing the binding issue. However the Xaml code looks like this:
<Page.Resources>
<DataTemplate x:Key="ThumbnailsTemplate">
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center"
VerticalAlignment="Center"
KeyDown="IsitenterThumb"
BorderBrush="LightSeaGreen"
BorderThickness="1"
<Image Source="{Binding thumb}"
x:Name="thumbimg"
Visibility="Visible"
Height="{Binding ItemSize, ElementName=page}" Width="{Binding ItemSize, ElementName=page}"
Stretch="Uniform"
Tapped="ThumbnailSelected"
DoubleTapped="CloseThumbnails"
/>
<TextBlock Text="{Binding name}" Margin="5,5"
Foreground="White" Width="{Binding ItemSize}"
/>
</StackPanel>
</DataTemplate>
</Page.Resources>
<GridView x:Name = "ctlThumbnails" Grid.Column="0"
BorderBrush="White" BorderThickness="2"
Grid.RowSpan="4" Grid.Row="0" Grid.ColumnSpan="3" Height ="auto" Width="auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Margin="30,30,30,30" KeyDown="IsitenterThumb"
DoubleTapped="CloseThumbnails"
ItemTemplate="{StaticResource ThumbnailsTemplate}">
</GridView>
And here is the C# code to affect the bound variable ItemSize
public event PropertyChangedEventHandler PropertyChanged;
public double ItemSize
{
get => _itemSize;
set
{
if (_itemSize != value)
{
_itemSize = value;
topcmdbarcontent.Text = "Thumb Size:" + _itemSize.ToString();
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ItemSize)));
}
}
}
private double _itemSize;
From this, when you change the value of ItemSize, through a ValueChanged event, for example, it does change the grid element size dynamically.
Related
In my xaml setup I have a Label, which should wrap its text. It is contained within a border, and I want the Label width to be the width of the border. I've tried to do this with the following binding on the label:
WidthRequest="{Binding Source={RelativeSource Mode=FindAncestor, AncestorType={x:Type Border}}, Path=Width}"
This has not worked though, and i suspect it hasn't because the Width that gets returned is NaN (I've written out the width of the border during runtime and it was NaN). But this is confusing to me, as I have a binding on the Border to the width of the Flexlayout which is working. Is there anything I'm missing and is there any better way to do this?
xaml:
<ScrollView Grid.Row="1">
<FlexLayout BindableLayout.ItemsSource="{Binding DisplayedUserActions}" JustifyContent="Start" Wrap="Wrap" Direction="Row">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Border FlexLayout.AlignSelf="Stretch" FlexLayout.Basis="{Binding Source={RelativeSource FindAncestor, AncestorType{x:Type ScrollView}}, Path=Width, Converter={StaticResource WidthToFlexlayoutBasisConverter}}">
<Grid RowDefinitions="*,*">
-- more content --
<Label Grid.Row="1" Text="{Binding Title}" LineBreakMode="WordWrap" HorizontalTextAlignment="Center" VerticalOptions="Center" HorizontalOptions="Center" TextColor="Black" Margin="5" WidthRequest="{Binding Source={RelativeSource Mode=FindAncestor, AncestorType={x:Type Border}}, Path=Width}"/>
</Grid>
</Border>
</DataTemplate>
</BindableLayout.ItemTemplate>
</FlexLayout>
</ScrollView>
You can use data binding to achieve the same width for Label and Border. Bind the Border and Label's WidthRequest properties to the TestWidth property in the same binding context. like this:
Xaml:
<StackLayout>
<StackLayout.BindingContext>
<local:MyViewModel/>
</StackLayout.BindingContext>
<Border BackgroundColor="Pink" WidthRequest="{Binding Testwidth}">
<Label x:Name="lable" Text="test1111111111111111" WidthRequest="{Binding Testwidth}"/>
</Border>
</StackLayout>
ViewModel:
public class MyViewModel : INotifyPropertyChanged
{
public double testwidth;
public event PropertyChangedEventHandler PropertyChanged;
public double Testwidth
{
get { return testwidth; }
set
{
if (testwidth != value)
{
testwidth = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Testwidth"));
}
}
}
public MyViewModel() { testwidth= 100; }
}
I want to select the list item when I click the button(Which is inside the list box for every row).
Now I have try like this:-
<ListBox Height="444"
ItemsSource="{Binding StudentDetails,Mode=TwoWay}"
HorizontalAlignment="Left" Margin="2,34,0,0"
Name="listBox1" VerticalAlignment="Top"
Width="476" BorderBrush="#00410D0D"
SelectedIndex="{Binding MemberPrivacy,Mode=TwoWay}"
SelectedItem="{Binding SelectedStudent, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Gray" Padding="5" BorderThickness="1">
<StackPanel Orientation="Horizontal">
<Border BorderBrush="Wheat" BorderThickness="1">
<Image Name="ListPersonImage" Source="{Binding PersonImage}" Height="100" Width="100" Stretch="Uniform" Margin="10,0,0,0"/>
</Border>
<TextBlock Text="{Binding FirstName}" Name="firstName" Width="200" Foreground="White" Margin="10,10,0,0" FontWeight="SemiBold" FontSize="22" />
<Image Height="50" Source="{Binding addImage}" HorizontalAlignment="Left" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="50" />
<Button Margin="-100,0,0,0" Height="80" Width="80" DataContext="{Binding DataContext, ElementName=listBox1}" Command="{Binding addPerson}" >
<Button.Background>
<ImageBrush ImageSource="{Binding addImage, Converter={StaticResource pathToImageConverter}}" Stretch="Fill" />
</Button.Background>
</Button>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My View Model:-
public ListBoxEventsViewModel()
{
addPerson = new ReactiveAsyncCommand();
addPerson.Subscribe(x =>
{
MessageBox.Show("Test Button Selected..");
});
}
Here I can show the message box when I click the button. But I can not select the list item. Please let me know to solve this problem.
Thanks in advance.
View Model:-
List box selected Item:-
public ListBoxEventsModel _SelectedStudent;
public ListBoxEventsModel SelectedStudent
{
get { return _SelectedStudent; }
set
{
this.RaiseAndSetIfChanged(x => x.SelectedStudent, value);
MessageBox.Show("Selected index==>" + SelectedStudent.FirstName);
}
}
Here it showing the selected name when I click the list item. But this same thing I want to write it for the button(addImage)
Bind the SelectedItem on the ListBox to a "SelectedItem" property on the ViewModel.
eg SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
then on the view model just add a property of SelectedItem, then you can just set that from in your subscribe.
PFB the code for datagrid in our silverlight app,i need to validate the column AttributeValue in each row based on other column value DatatypeName, for example the DatatypeNamecolumn value for a particular row is int the AttributeValue column in the same row should allow user only int ,if user enters other than int the cell should throw validation exception.Please help
<sdk:DataGrid Margin="0,0,0,50" Grid.Row="1" Grid.Column="0" RowStyle="{StaticResource DataGridRowStyle1}" Style="{StaticResource DataGridStyle1}" IsReadOnly="True" Foreground="{StaticResource GrayBrush}" HorizontalScrollBarVisibility="Hidden" Name="dgKpiAttributes" MinHeight="5" VerticalAlignment="Stretch" FontSize="13.333" FontFamily="Segoe UI" AutoGenerateColumns="False" GridLinesVisibility="None" >
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn Header=" " >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="chkSelect"
VerticalAlignment="Center" IsChecked="False" HorizontalAlignment="Center" HorizontalContentAlignment="Center"/>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="AttributeName" SortMemberPath="AttributeName" Width="50*" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel VerticalAlignment="Center">
<TextBlock x:Name="txtAttributeName" TextWrapping="Wrap" Padding="4" Text="{Binding AttributeName}" HorizontalAlignment="Center" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="AttributeValue" SortMemberPath="AttributeValue" Width="80*" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel VerticalAlignment="Center">
<TextBox x:Name="AttributeValue" Margin="0,0,10,0" HorizontalAlignment="Stretch" Text="{Binding AttributeValue}" TextWrapping="Wrap" />
</StackPanel>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="DataType" SortMemberPath="DataTypeName" Width="50*">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel VerticalAlignment="Center">
<TextBox x:Name="DatatypeName" HorizontalAlignment="Stretch" TextWrapping="Wrap" IsEnabled="False" Text="{Binding DataTypeName}" />
</StackPanel>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
Well, from your code I can see your class is like this (correct me if I'm mistaken):
class MyClass
{
public string AttributeName {get;set;}
public string AttributeValue {get;set;}
public string DatatypeName {get;set;}
}
In silverligth, I suppose there is a way to check another cells in the same row in a datagrid, but since you are working with bindings, you do not need that, you can work directly in your data object:
class MyClass
{
public string AttributeName {get;set;}
public string DatatypeName {get;set;}
private string _AttributeValue;
public string AttributeValue {
get{
return _AttributeValue;
}
set{
if (validate(DatatypeName,value)){
//Do something if validation is a success
_AttributeValue = value;
}
else{
//Do something if validation fails
}
}
}
bool validate(string typename,string value){
//do your validation, return true or false
return true
}
}
This way you do not need to concern yourself with traversing the UI, only with the data.
I have written a content control with an Int Dependency Property in the content Control.
The Control has a default style which contains the Template for the control.
Now the problem i face is, No matter what the dependency property's value is , when rendered it always shows me a zero
Here's the sample Code snippet:
<ControlTemplate x:Key="ControlTemplate2" TargetType="My:Control">
<Grid x:Name="grid" Width ="128" Height="128>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal" Grid.Row="1">
<TextBlock x:Name="tbxTileCount" DataContext="{TemplateBinding TileCount}"
Text="{Binding}" Margin="10,0,0,0"
Foreground="White" VerticalAlignment="Center" FontSize="48" FontFamily="Segoe WP">
<TextBlock.RenderTransform>
<CompositeTransform/>
</TextBlock.RenderTransform>
</TextBlock>
</StackPanel>
</Grid></Grid></ControlTemplate>
/// <summary>
/// Count to be displayed
/// </summary>
public int Count
{
get { return (int)GetValue(CountProperty); }
set { SetValue(CountProperty, value); }
}
public static readonly DependencyProperty CountProperty =
DependencyProperty.Register("Count",
typeof(int),
typeof(Control),
null);
Eventhough the dependency property is set to default value, the DataContext of the textblock is set to 0
What have i missed here?
I could get this to work.
Here's how I got it to work :
Apparently For Silverlight 4, This is the way you associate control properties to the default Template.
<ControlTemplate x:Key="ControlTemplate2" TargetType="My:Control">
<Grid x:Name="grid" Width ="128" Height="128>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal" Grid.Row="1">
<TextBlock x:Name="tbxTileCount" Text="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Count}"
Margin="10,0,0,0" Foreground="White" VerticalAlignment="Center" FontSize="48" FontFamily="Segoe WP">
<TextBlock.RenderTransform>
<CompositeTransform/>
</TextBlock.RenderTransform>
</TextBlock>
</StackPanel>
</Grid>
</ControlTemplate>
I'm currently playing with the Silverlight(Beta 2) Datagrid control. Before I wired up the SelectionChanged event, the grid would sort perfectly by clicking on the header. Now, when the grid is clicked, it will fire the SelectionChanged event when I click the header to sort. Is there any way around this?
In a semi-related topic, I'd like to have the SelectionChanged event fire when I click on an already selected item (so that I can have a pop-up occur to allow the user to edit the selected value). Right now, you have to click on a different value and then back to the value you wanted in order for it to pop up. Is there another way?
Included is my code.
The Page:
<UserControl x:Class="WebServicesApp.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
Width="1280" Height="1024" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" x:Name="OurStack" Orientation="Vertical" Margin="5,5,5,5">
<ContentControl VerticalAlignment="Center" HorizontalAlignment="Center">
<StackPanel x:Name="SearchStackPanel" Orientation="Horizontal" Margin="5,5,5,5">
<TextBlock x:Name="SearchEmail" HorizontalAlignment="Stretch" VerticalAlignment="Center" Text="Email Address:" Margin="5,5,5,5" />
<TextBox x:Name="InputText" HorizontalAlignment="Stretch" VerticalAlignment="Center" Width="150" Height="Auto" Margin="5,5,5,5"/>
<Button x:Name="SearchButton" Content="Search" Click="CallServiceButton_Click" HorizontalAlignment="Center" VerticalAlignment="Center" Width="75" Height="Auto" Background="#FFAFAFAF" Margin="5,5,5,5"/>
</StackPanel>
</ContentControl>
<Grid x:Name="DisplayRoot" Background="White" ShowGridLines="True"
HorizontalAlignment="Center" VerticalAlignment="Center" MaxHeight="300" MinHeight="100" MaxWidth="800" MinWidth="200"
ScrollViewer.HorizontalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollBarVisibility="Visible">
<data:DataGrid ItemsSource="{Binding ''}" CanUserReorderColumns="False" CanUserResizeColumns="False"
AutoGenerateColumns="False" AlternatingRowBackground="#FFAFAFAF" SelectionMode="Single"
HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,5,5,5" x:Name="IncidentGrid" SelectionChanged="IncidentGrid_SelectionChanged">
<data:DataGrid.Columns>
<data:DataGridTextColumn DisplayMemberBinding="{Binding Address}" Header="Email Address" IsReadOnly="True" /> <!--Width="150"-->
<data:DataGridTextColumn DisplayMemberBinding="{Binding whereClause}" Header="Where Clause" IsReadOnly="True" /> <!--Width="500"-->
<data:DataGridTextColumn DisplayMemberBinding="{Binding Enabled}" Header="Enabled" IsReadOnly="True" />
</data:DataGrid.Columns>
</data:DataGrid>
</Grid>
</StackPanel>
<Grid x:Name="EditPersonPopupGrid" Visibility="Collapsed">
<Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.765" Fill="#FF8A8A8A" />
<Border CornerRadius="30" Background="#FF2D1DCC" Width="700" Height="400" HorizontalAlignment="Center" VerticalAlignment="Center" BorderThickness="1,1,1,1" BorderBrush="#FF000000">
<StackPanel x:Name="EditPersonStackPanel" Orientation="Vertical" Background="White" HorizontalAlignment="Center" VerticalAlignment="Center" Width="650" >
<ContentControl>
<StackPanel x:Name="EmailEditStackPanel" Orientation="Horizontal">
<TextBlock Text="Email Address:" Width="200" Margin="5,0,5,0" />
<TextBox x:Name="EmailPopupTextBox" Width="200" />
</StackPanel>
</ContentControl>
<ContentControl>
<StackPanel x:Name="AppliesToDropdownStackPanel" Orientation="Horizontal" Margin="2,2,2,0">
<TextBlock Text="Don't send when update was done by:" />
<StackPanel Orientation="Vertical" MaxHeight="275" MaxWidth="350" >
<TextBlock x:Name="SelectedItemTextBlock" TextAlignment="Right" Width="200" Margin="5,0,5,0" />
<Grid x:Name="UserDropDownGrid" MaxHeight="75" MaxWidth="200" Visibility="Collapsed" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Hidden" >
<Rectangle Fill="White" />
<Border Background="White">
<ListBox x:Name="UsersListBox" SelectionChanged="UsersListBox_SelectionChanged" ItemsSource="{Binding UserID}" />
</Border>
</Grid>
</StackPanel>
<Button x:Name="DropDownButton" Click="DropDownButton_Click" VerticalAlignment="Top" Width="25" Height="25">
<Path Height="10" Width="10" Fill="#FF000000" Stretch="Fill" Stroke="#FF000000" Data="M514.66669,354 L542.16669,354 L527.74988,368.41684 z" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="1,1,1,1"/>
</Button>
</StackPanel>
</ContentControl>
<TextBlock Text="Where Clause Condition:" />
<TextBox x:Name="WhereClauseTextBox" Height="200" Width="800" AcceptsReturn="True" TextWrapping="Wrap" />
<ContentControl>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<Button x:Name="TestConditionButton" Content="Test Condition" Margin="5,5,5,5" Click="TestConditionButton_Click" />
<Button x:Name="Save" Content="Save" HorizontalAlignment="Right" Margin="5,5,5,5" Click="Save_Click" />
<Button x:Name="Cancel" Content="Cancel" HorizontalAlignment="Right" Margin="5,5,5,5" Click="Cancel_Click" />
</StackPanel>
<TextBlock x:Name="TestContitionResults" Visibility="Collapsed" />
</StackPanel>
</ContentControl>
</StackPanel>
</Border>
</Grid>
</Grid>
And the call that occurs when the grid's selection is changed:
Private Sub IncidentGrid_SelectionChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
If mFirstTime Then
mFirstTime = False
Else
Dim data As SimpleASMX.EMailMonitor = CType(IncidentGrid.SelectedItem, SimpleASMX.EMailMonitor)
Dim selectedGridItem As SimpleASMX.EMailMonitor = Nothing
If IncidentGrid.SelectedItem IsNot Nothing Then
selectedGridItem = CType(IncidentGrid.SelectedItem, SimpleASMX.EMailMonitor)
EmailPopupTextBox.Text = selectedGridItem.Address
SelectedItemTextBlock.Text = selectedGridItem.AppliesToUserID
WhereClauseTextBox.Text = selectedGridItem.whereClause
IncidentGrid.SelectedIndex = mEmailMonitorData.IndexOf(selectedGridItem)
End If
If IncidentGrid.SelectedIndex > -1 Then
EditPersonPopupGrid.Visibility = Windows.Visibility.Visible
Else
EditPersonPopupGrid.Visibility = Windows.Visibility.Collapsed
End If
End If
End Sub
Sorry if my code is atrocious, I'm still learning Silverlight.
That looks like a Silverlight bug to me. I've just tried it and what's happening on my end is that the SelectionChanged event fires twice when you click the column header and to make matters worse, the index of the selected item doesn't stay synched with the currently selected item.
I'd suggest you work your way around it by using the knowledge that the first time SelectionChanged fires, the value of the datagrid's SelectedItem property will be null
Here's some sample code that at least lives with the issue. Your SelectionChanged logic can go in the if clause.
public partial class Page : UserControl
{
private Person _currentSelectedPerson;
public Page()
{
InitializeComponent();
List<Person> persons = new List<Person>();
persons.Add(new Person() { Age = 5, Name = "Tom" });
persons.Add(new Person() { Age = 3, Name = "Lisa" });
persons.Add(new Person() { Age = 4, Name = "Sam" });
dg.ItemsSource = persons;
}
private void SelectionChanged(object sender, EventArgs e)
{
DataGrid grid = sender as DataGrid;
if (grid.SelectedItem != null)
{
_currentSelectedPerson = grid.SelectedItem as Person;
}
else
{
grid.SelectedItem = _currentSelectedPerson;
}
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
Frozen Columns in Silverlight DataGrid..
http://dotnetdreamer.wordpress.com/2009/01/31/silverlight-2-datagrid-frozen-columns/
There's a bugfix for the first issue you mentioned (selection changed event getting fired on resort).
See the following URL for Microsoft's patch:
http://www.microsoft.com/downloads/details.aspx?familyid=084A1BB2-0078-4009-94EE-E659C6409DB0&displaylang=en
This worked, but now if I sort twice, on the first one it sorts, and then does the popup as the first selected item of the grid . If I close the popup grid, and then try to sort a second time, it stack overflows, and crashes firefox out.
I'm thinking I may need to rethink working in silverlight until the system gets a bit more stable.
Thanks for the answer Hovito!