I have an custom textbox that I got from http://blog.roboblob.com/2010/07/16/custom-silverlight-textbox-control-that-immediately-updates-databound-text-property-in-twoway-binding/comment-page-1/:
public class ImmediateTextBox : TextBox
{
public ImmediateTextBox()
{
this.Loaded += ImmediateTextBox_Loaded;
}
void ImmediateTextBox_Loaded(object sender, RoutedEventArgs e)
{
this.GotFocus += ImmediateTextBox_GotFocus;
this.TextChanged += new TextChangedEventHandler(ImmediateTextBox_TextChanged);
}
void ImmediateTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox txt = sender as TextBox;
if (txt != null)
{
BindingExpression bindExp = txt.GetBindingExpression(TextBox.TextProperty);
if (bindExp != null)
{
bindExp.UpdateSource();
}//if
}//if
}
void ImmediateTextBox_GotFocus(object sender, RoutedEventArgs e)
{
this.SelectAll();
}
}
In my xaml I am using this, and it works fine, except when I have it nested and the parent container has a ImmediateTextBox:
<ItemsControl Grid.Column="1" ItemsSource="{Binding Path=LstForecast}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<customControls:ImmediateTextBox Padding="8" Height="36" Text="{Binding Path=DForecastQuantityShippedTotal,
StringFormat=\{0:n0\},
Mode=TwoWay,
Converter={StaticResource StringToNullableDoubleConverter}}"
Width="70" IsEnabled="{Binding Path=IsForecastUserEditable}"/>
<!--Weeks-->
<ItemsControl ItemsSource="{Binding Path=LstWeeks}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<customControls:ImmediateTextBox Padding="8" Width="70" Height="36"
Text="{Binding Path=DForecastQuantityShippedTotal, StringFormat=\{0:n0\}, Mode=TwoWay, Converter={StaticResource StringToNullableDoubleConverter}}"
IsEnabled="{Binding Path=IsForecastUserEditable}"/>
<!--days data-->
<ItemsControl ItemsSource="{Binding Path=LstDays}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<customControls:ImmediateTextBox Padding="8" Width="70" Height="36"
Text="{Binding Path=DForecastAutoManual,
StringFormat=\{0:n0\},
Mode=TwoWay,
Converter={StaticResource StringToNullableDoubleConverter}}"
IsEnabled="{Binding Path=IsForecastUserEditable}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!--end days data-->
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!--end weeks-->
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
At the lowest level it gets really funky. modifying the previous and sometimes the following generated textboxes. If I use an autocompletebox, of course it works. The problem is that I am wanting to add behaviors to the textbox for copy/paste/selectall, etc that I can't do with the autocompletebox, since there is no selectedtext or a selectall() method. Also I noticed in the RoutedEventArgs, the originalsource is null. I figured using that would cause it to work, but no. Any help? thanks in advance.
Okay so I figured it out. I have each text-box bound to properties. When any one of these text-boxes are modified then the bound properties of the ViewModel update each other. When that happens they update the text-box where it occurs and not just the property, because it is a 2-way binding. So when there is an update that is caused by the user's input it updates. It shouldn't when the user doesn't type anything in that text-box (when the text-box is being updated from the algorithm.
My solution is creating a boolean property "isUser" in ImmediateTextBox. When my overridden OnKeyDown or OnMouseLeftButtonPressed are called I set isUser to true. When the text changes from the user typing in or pasting in something, then i update the binding and set isUser to false.
Related
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.
I am working on a UWP application, trying to implement ItemClick event on a GridView, however, when I click on an Item, nothing happens.
The relevant code is below:
Book.xaml:
<Page.DataContext>
<vm:BookViewModel x:Name="ViewModel" />
</Page.DataContext>
<GridView Grid.Row="1"
Padding="18"
ItemsSource="{Binding Source={StaticResource BookViewSource}}"
IsItemClickEnabled="True"
ItemClick="{x:Bind ViewModel.BookGroups_OnItemClick}">
BookViewModel.cs:
public void NavigateToDetails(string url)
{
NavigationService.Navigate(typeof(Views.DetailPage), url);
}
public void BookGroups_OnItemClick(object sender, ItemClickEventArgs e)
{
var bookHeader = (BookGroup)e.ClickedItem;
NavigateToDetails(bookHeader.url);
}
I would really appreciate your help, thank you!
EDIT : Book.xaml GrdivView source:
<GridView Grid.Row="1"
Padding="18"
ItemsSource="{Binding Source={StaticResource BookViewSource}}"
IsItemClickEnabled="True"
ItemClick="{x:Bind ViewModel.BookGroups_OnItemClick}"
>
<GridView.ItemTemplate>
<DataTemplate>
<Grid Width="250" Height="250" >
<Border VerticalAlignment="Bottom" Background="#AA000000">
<TextBlock Text="{Binding name}" Margin="12" Foreground="White"/>
</Border>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding name}" Margin="-12,0,0,0"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
I have copied your code 1:1 into a new project and the NavigateToDetails method does get called. Please try to put a breakpoint in the method to see if it gets hit. If it does, there might be a problem with the NavigationService. Otherwise, the problem is very likely in the GridView.ItemTemplate - it may be possible that there is a control that handles the click event so that it doesn't bubble up to the GridView at all.
So finally as I deleted the following part from Book.xaml, the item click works fine:
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding name}" Margin="-12,0,0,0"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</GridView.GroupStyle>
I did not find out what caused the problem, but now it works.
Thank you for your help and time :)
I'm trying to use a SemanticZoom in my Windows 8 application and it seems to not work.
Do I do something wrong here ?
I tried pretty much everything I thought that could work but in vain : removed the rowdefinitions, removed the style, removed the templates but still not working...
<Grid Style="{StaticResource LayoutRootStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<SemanticZoom Grid.RowSpan="2">
<SemanticZoom.ZoomedInView>
<GridView x:Name="itemGridView"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Grouped Items"
Padding="116,137,40,46"
ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
SelectionMode="None"
IsSwipeEnabled="True"
IsItemClickEnabled="True"
ItemTemplate="{StaticResource GridViewItemTemplateZoomIn}"
ItemsPanel="{StaticResource GridViewItemsPanelTemplate}"
helpers:ItemClickCommand.Command="{Binding ServiceClickCommand}">
<GridView.GroupStyle>
<GroupStyle HidesIfEmpty="True">
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Margin="1,0,10,6">
<Button AutomationProperties.Name="Group Title"
Style="{StaticResource TextPrimaryButtonStyle}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"
Margin="3,-7,10,10"
Style="{StaticResource GroupHeaderTextStyle}" />
<TextBlock Text="{StaticResource ChevronGlyph}"
FontFamily="Segoe UI Symbol"
Margin="0,-7,0,10"
Style="{StaticResource GroupHeaderTextStyle}" />
</StackPanel>
</Button>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical"
Margin="0,0,80,0" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
</SemanticZoom.ZoomedInView>
<SemanticZoom.ZoomedOutView>
<GridView x:Name="itemZoomOutGridView"
ScrollViewer.IsHorizontalScrollChainingEnabled="False"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Grouped Items"
Padding="116,175,40,46"
SelectionMode="None"
IsSwipeEnabled="True"
IsItemClickEnabled="True"
ItemTemplate="{StaticResource GridViewItemTemplateZoomOut}"
ItemsPanel="{StaticResource GridViewItemsPanelTemplate}"
ItemsSource="{Binding ServiceCategories}">
</GridView>
</SemanticZoom.ZoomedOutView>
</SemanticZoom>
Thank you :)
If I understand your problem correctly, the semanticView in itself is working (you can zoom in and zoom out). But when you zoom back in the GridView items are the same and doesn't change according to the ZoomedOutView GridView item you selected.
But with your XAML I think this is normal behaviour, because when you select a category the binding on your gridview in zoomedInView doesn't change.
ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
My first advice would be to bind the ItemsSource to a list in your ViewModel not use a staticRessource.
Secondly you can change the SemanticView this way:
<SemanticZoom Grid.RowSpan="2" ViewChangeStarted="SemanticZoomChanged" >
And in your code behind add that:
private void SemanticZoomChanged(object sender, SemanticZoomViewChangedEventArgs e)
{
// First we check that we are going from ZoomedOut to ZoomedIn
if (e.IsSourceZoomedInView == false)
{
// I call a method in my ViewModel giving the chosen category in parameter
DefaultViewModel.OnSelectedCategoryChanged(e.SourceItem.Item.ToString());
}
}
Using MVVM I know it's ugly to have code in code-behind but this is not a lot and we are calling a method in the ViewModel to do the logic so it's still following MVVM design pattern.
And last we add a function in the ViewModel that will change the ItemsSource of the ZoomedInView
OnSelectedCategoryChanged(string chosenCategory)
{
// Here change the value of your groupedItemsViewSource list
GroupedItemsViewSource = ....;
}
Now it should work as you want to.
I am working with listview control in win8. I want to add an event when I hold on the item, and delete the item.
the xaml and event code like this:
<ListView x:Name="ImageList" VerticalAlignment="Bottom" Background="LightGray" Width="1050" BorderBrush="Black" BorderThickness="2" Grid.Column="1"
Holding="ListView_Hold1" SelectionChanged="OnSelectedChanged" SelectionMode="Single" Height="152" ScrollViewer.HorizontalScrollBarVisibility="Auto" ItemContainerStyle="{StaticResource ListViewItemStyle1}" Style="{StaticResource ListViewStyle1}">
<ListView.ItemTemplate>
<DataTemplate>
<Image Opacity="0.7" Width="150" Height="125" Stretch="UniformToFill" Source="{Binding}" />
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
private async void ListView_Hold1(object sender, Windows.UI.Xaml.Input.HoldingRoutedEventArgs e)
{...}
It seems that I can not get any information from holdingroutdEventArgs but the attribute of originalsource. But it is the image and no way access to iteml
I have found a relative question: "how to get the clicked item in the listview". it can be solved by getting the attribute of selecteditem.
anyone can help me ? give me some clue.
You should be able to get it from the HoldingRoutedEventArgs.OriginalSource.DataContext, in your case: (Assuming that the ListView.ItemSource is a list of ImageModel)
private async void ListView_Hold1(object sender, Windows.UI.Xaml.Input.HoldingRoutedEventArgs args)
{
var source = (FrameworkElement)args.OriginalSource;
var imageModel = (ImageModel)source.DataContext;
}
You can get the index of the item using the SelectedIndex property (but for these work you have to select, by pressing, and after hold the item)
int i = imageList.SelectedIndex;
So to delete the item you can use the RemoveAt() method
imageList.Items.RemoveAt(i);
I am using the following code to create hyperlink column in xceed grid in wpf. When am binding a datatable to xceed grid, the value is binding but the hyperlink is not created. Please help me.
<DataTemplate x:Key="ButtonTemplate">
<TextBlock>
<Hyperlink Click="Hyperlink_Click">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=.}"/>
<TextBlock Text="{Binding RelativeSource={RelativeSource
AncestorType= {x:Type xcdg:DataRow}},Path=DataContext.[Documents]}"/>
</StackPanel>
</Hyperlink>
</TextBlock>
</DataTemplate>
<xcdg:Column FieldName="ColumnTest" Title="Test">
<xcdg:Column.CellContentTemplate>
<DataTemplate>
<TextBlock>
<Hyperlink RequestNavigate="Hyperlink_RequestNavigate" NavigateUri="{Binding .}">
<TextBlock Text="{Binding .}" />
</Hyperlink>
</TextBlock>
</DataTemplate>
</xcdg:Column.CellContentTemplate>
</xcdg:Column>
You will need to add the RequestNavigate event handler so that when the hyperlink is clicked, you can send the request. This should open up your default browser and go straight to your page.
here is the code for the event handler:
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
e.Handled = true;
}