I'm trying to create a reactive application in F# using WPF and I have encountered some problems with accessing XAML elements from the code.
In the XAML-file I have created a grid containing 16 columns and rows each:
<StackPanel Name="cellStackPanel">
<Grid Name="cellGrid" Height="500" Width="500" Margin="10,10,10,10" Background="#CCCCCC">
<Grid.Resources>
<Style TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border x:Name="border" Background="#FFFFFFFF" Margin="1,1,1,1">
<ContentPresenter x:Name="contentPresenter"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Background" TargetName="border" Value="Black"/>
</Trigger>
<Trigger Property="Control.IsMouseOver" Value="true">
<Setter Property="Background" TargetName="border" Value="#CCCCCC"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
</StackPanel>
In F#, I traverse through the grid and programatically initialize every cell into ToggleButtons:
let initCell (x,y) (grid : Grid) =
let cell = ToggleButton()
Grid.SetColumn(cell, x)
Grid.SetRow(cell, y)
ignore (grid.Children.Add(cell))
Now I want to create an observable (to wait for in a recursive asynchronous loop) for clicking any of my ToggleButtons. I can access the grid element itself within the code but my problem is that I don't know how to access its child elements that I've created programatically. I was thinking of a, perhaps rudimentary, solution which is to catch the click event from the entire grid, and at the same time get the mouse coordinates to calculate which cell was clicked. But that is probably not a good way to do this.
I hope my question is understandable, otherwise, let me know.
As I said in the comment easier to use FsXAML + FSharp.ViewModule.
I don't quite understand what you want to, so a simple example:
<Grid>
<ListBox
ItemsSource="{Binding Cells}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="{Binding N}" Columns="{Binding N}"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<ToggleButton Content="{Binding Text}"
IsChecked="{Binding IsChecked}"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}},
Path=DataContext.ClickCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self},Path=DataContext}"
>
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border x:Name="border" Background="Wheat" Margin="0">
<ContentPresenter x:Name="contentPresenter"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Background" TargetName="border" Value="DarkGreen"/>
</Trigger>
<Trigger Property="Control.IsMouseOver" Value="true">
<Setter Property="Background" TargetName="border" Value="#CCCCCC"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ToggleButton.Style>
</ToggleButton>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Padding" Value="0" />
<Setter Property="Focusable" Value="False"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
You can use ItemsControl instead of ListBox, but configuring it will take some time =)
.fs:
type State = {mutable IsChecked:bool; Text:string}
type MainViewModel() as self =
inherit ViewModelBase()
let n = 16
let data = [1..n*n] |> List.map(fun i -> {IsChecked = false; Text = string i})
let click (state:obj) =
let st = (state :?> State)
MessageBox.Show(sprintf "%s %b" st.Text st.IsChecked ) |> ignore
let clickcommand = self.Factory.CommandSyncParam(click)
member __.ClickCommand = clickcommand
member __.Cells = data
member __.N = n
Thus, you can do anything with your object in the function click.
P.S. I allowed myself to change a little your ToggleButton style to the picture was more clearer.
I'm not a big fan of 3rd party solutions as an answer. If I understand your question, you are trying to access an element that was specified in your XAML. This can be easily done by converting your XAML to a string type then using:
let xamlBytes = Encoding.UTF8.GetBytes(xamlString)
let xamlStream = new MemoryStream(xamlBytes)
let xamlRoot = XamlReader.Load(xamlStream)
let rootElement = xamlRoot :?> FrameworkElement
let elementYouNeed = rootElement.FindName("nameOfElementYouNeed") :?> TypeOfElementYouNeed
Your case might be slightly different but this is the general idea.
Related
I'm trying to build a simple 3x3 grid in Silverlight with a button in each grid cell. The grid definition is below. When I add button to the grid they never fill the 130x130 grid cell. I set the margin and padding to 0 on the buttons as well as setting their horizontal and vertical alignment to Stretch.
<Grid x:Name="Test" ShowGridLines="True" HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="130"></RowDefinition>
<RowDefinition Height="130"></RowDefinition>
<RowDefinition Height="130"></RowDefinition>
<RowDefinition Height="130"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="130"></ColumnDefinition>
<ColumnDefinition Width="130"></ColumnDefinition>
<ColumnDefinition Width="130"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Style x:Key="OperandButton" TargetType="Button">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Background" Value="{StaticResource PhoneAccentColor}" />
<Setter Property="FontSize" Value="50" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
</Style>
<Button Content="10" Style="{StaticResource OperandButton}" Grid.Row="0" Grid.Column="0" />
<Button Content="3" Style="{StaticResource OperandButton}" Grid.Row="0" Grid.Column="1" />
<Button Content="7" Style="{StaticResource OperandButton}" Grid.Row="0" Grid.Column="2" />
Your code should just work fine. Just try this code as it is.
<Grid x:Name="Test" ShowGridLines="True" HorizontalAlignment="Center" >
<Grid.Resources>
<Style x:Key="OperandButton" TargetType="Button">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Background" Value="Blue" />
<Setter Property="FontSize" Value="50" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="130"></RowDefinition>
<RowDefinition Height="130"></RowDefinition>
<RowDefinition Height="130"></RowDefinition>
<RowDefinition Height="130"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"></ColumnDefinition>
<ColumnDefinition Width="130"></ColumnDefinition>
<ColumnDefinition Width="130"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Content="10" Style="{StaticResource OperandButton}" Grid.Row="0" Grid.Column="0" />
<Button Content="3" Style="{StaticResource OperandButton}" Grid.Row="0" Grid.Column="1" />
<Button Content="7" Style="{StaticResource OperandButton}" Grid.Row="0" Grid.Column="2" />
</Grid>
Let me know if you still not getting it.
Try the following,
When you open your project in Blend. Right click the button, go to edit template, edit current. You'l find that every button has a grid and a container. Make the size of both equal then, you'l see the default border's size same as the buttons size.
The same template can be used for other buttons too.
Now try enveloping the buttons in the grid.
Looking at the template in blend solved the problem. The following property was set on the Border:
Margin="{StaticResource PhoneTouchTargetOverhang}"
Once this was set to 0, the grid was perfect. Thanks for the guidance.
Try this, it's must not specified VerticalAlignment Or HorizontalAlignment.
Margin="-10"
I have been trying to change the background color of wpf's default datepicker. Right now it is dark blue with black text and client wants it changed to white. I have been coding a lot and nothing seems to work.
Pls help. thanks
<Style x:Key="DateStyle" TargetType="{x:Type DatePcker}" BasedOn="{x:Null}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" Value="Yellow" />
</Trigger>
<Trigger Property="IsReadOnly" Value="True">
<Setter Property="Background" Value="White" />
</Trigger>
</Style.Triggers>
<Setter Property="Background" Value="Transparent" />
<Setter Property="CharacterCasing" Value="Upper"/>
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="FontSize" Value="11" />
</Style>
here's my datepicker
<DatePicker Grid.Column="2" Grid.ColumnSpan="2" Grid.Row="4" Height="25" HorizontalAlignment="Left" TabIndex="3"
Name="dpFillingDateFrom" VerticalAlignment="Center" Width="97" Text="12/12/2011" SelectedDateFormat="Short"/>
Just go through http://msdn.microsoft.com/en-us/magazine/dd882520.aspx.
Its not straight forward to change the background color of wpf's default datepicker but you can follow below steps
1) Date picker has a CalenderStye Property so override Calender Default ControlTemplate
2) In Calender control template, there is CalenderItemStyle where you can override CalenderItemStyle defaulttemplate. In this you can customize the background colors as well as header buttons.
<Style x:Key="ItemStyle" TargetType="primitives:CalendarItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="primitives:CalendarItem">
<ControlTemplate.Resources>
<DataTemplate x:Key="DayTitleTemplate">
<TextBlock Text="{Binding}"
HorizontalAlignment="Center" />
</DataTemplate>
</ControlTemplate.Resources>
<DockPanel Name="PART_Root"
LastChildFill="True">
<Button x:Name="PART_PreviousButton"
DockPanel.Dock="Left"
Content="<"
Focusable="False" />
<Button x:Name="PART_NextButton"
DockPanel.Dock="Right"
Content=">"
Focusable="False" />
<Button x:Name="PART_HeaderButton"
DockPanel.Dock="Top"
FontWeight="Bold"
Focusable="False" />
<Grid>
<Grid x:Name="PART_MonthView"
Visibility="Visible">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
</Grid>
<Grid x:Name="PART_YearView"
Visibility="Hidden">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
</Grid>
</Grid>
<Rectangle x:Name="PART_DisabledVisual" Opacity="0" Visibility="Collapsed" Fill="#A5FFFFFF"/>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="PART_DisabledVisual" Property="Visibility" Value="Visible" />
</Trigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type toolkit:Calendar}}, Path=DisplayMode}" Value="Year">
<Setter TargetName="PART_MonthView" Property="Visibility" Value="Hidden" />
<Setter TargetName="PART_YearView" Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type toolkit:Calendar}}, Path=DisplayMode}" Value="Decade">
<Setter TargetName="PART_MonthView" Property="Visibility" Value="Hidden" />
<Setter TargetName="PART_YearView" Property="Visibility" Value="Visible" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="pp" TargetType="toolkit:Calendar">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="toolkit:Calendar">
<StackPanel Name="PART_Root"
Orientation="Horizontal">
<primitives:CalendarItem
Name="PART_CalendarItem"
Style="{StaticResource ItemStyle}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
VerticalAlignment="Center" />
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Margin="4 4 0 4">
<ScrollViewer
VerticalScrollBarVisibility="Auto"
Height="{Binding ElementName=PART_CalendarItem,
Path=ActualHeight}"
Width="100">
<ItemsControl
ItemsSource=
"{Binding RelativeSource={RelativeSource
AncestorType=toolkit:Calendar},
Path=SelectedDates}" />
</ScrollViewer>
</Border>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<toolkit:DatePicker CalendarStyle="{StaticResource pp}" Margin="0,0,0,242"></toolkit:DatePicker>
I have something like this:
<MyView>
<Style TargetType="Border" x:Key="Module">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="Gray" />
<Setter Property="Padding" Value="10" />
<Setter Property="Margin" Value="10" />
</Style>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Name="Border1" Style="{StaticResource Module}">
<!--some controls with non-fixed width-->
</Border>
<Border Grid.Row="1" Name="Border2" Style="{StaticResource Module}">
<!--some controls with non-fixed width-->
</Border>
<Border Grid.Column="1" Grid.RowSpan="2" Style="{StaticResource Module}" Name="Border3">
<!--some controls with non-fixed width-->
</Border>
</Grid>
</MyView>
The controls inside Border1 and Border2 might have different width, so their borders will also have different width, which doesn't look good. How do I force Border1 and Border2 border to have same width so it would look better?
The solution of setting same width manually doesn't count because the width of child controls of Border1 and Border2 may vary.
And the content of Border3 just eats up all available space, and this is fine.
Add <Setter Property="HorizontalAlignment" Value="Stretch" /> to your Border Style
I have two expanders in one grid row but in distinct columns. How can I expand each of it to the full row but not on column only.
<Grid x:Name="mainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90"/>
<ColumnDefinition Width="90"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition MinHeight="40" />
<RowDefinition MinHeight="40" />
</Grid.RowDefinitions>
<Controls:Expander Grid.Row="0" Grid.Column="0" x:Name="expander2" Header="Header1"
MinHeight="33" Padding="3">
<TextBlock Text="SomeText1" />
</Controls:Expander>
<Controls:Expander Grid.Row="0" Grid.Column="1" x:Name="expander1" Header="Header2"
MinHeight="33" Padding="3">
<TextBlock Text="SomeText2" />
</Controls:Expander>
</Grid>
expander1 and expander2 should expand to the whole row 0.
Introduce the triggers for Expanders that check their IsExpanded property and set their Grid.RowSpan as 2.
<Style TargetType="{x:Type Expander}">
<Style.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Setter Property="Grid.RowSpan" Value="2" />
</Trigger>
</Style.Triggers>
</Style>
For silverlight
<Style TargetType="{x:Type Expander}">
<Setter Property="Grid.RowSpan"
Value="{Binding IsExpanded,
RelativeSource={RelativeSource
Self},
Converter={StaticResource
local:ExpansionToRowSpanConverter}}"
</Style>
Code behind ... (this is just for illustration)
ExpansionToRowSpanConverter.Convert(....)
{
return (bool)value ? 2 : 1;
}
Does this work for you?
I am having a Grid in WPF application.
I want to display all the text block on the first column in the grid to be aligned to the right.
so I thought I could do it with ColumnDefinition and Style like this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition>
<ColumnDefinition.Resources>
<Style TargetType={x:Type TextBlock}">
<Setter Property=....../>
</Style..
.....
But This is is not working
Any idea why?
Is that what you want?
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Grid.Column" Value="0" />
<Setter Property="TextAlignment" Value="Right" />
</Style>
</Grid.Resources>
<TextBlock Text="foo" Grid.Row="0"/>
<TextBlock Text="bar" Grid.Row="1" />
</Grid>
You may have to try a PropertyTrigger, something like the following :
<Grid.Resources>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<Trigger Property="Grid.Column" Value="0">
<Setter Property="TextAlignment" Value="Right"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>