Lets say you want to add a new element to a Grid with the following code:
ExpanderView newExpander = new ExpanderView();
newExpander.Name = name;
newExpander.Header = header;
newExpander.FontSize = 40;
if (row == 0)
newExpander.IsExpanded = true;
foreach (Item li in items)
{
CheckBox tb = new CheckBox();
tb.Content = content;
tb.FontSize = 20;
newExpander.Items.Add(tb);
}
MyGrid.Children.Add(newExpander);
Grid.SetRow(newExpander, row);
And now the grid in xaml:
<Grid x:Name="MyGrid">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
</Grid>
Now the last line Grid.SetRow(newExpander, row) in the cs code portion,
How can you tell it which grid you want to set the new row for if you have multiple grids in the .xaml code?
The following code
Grid.SetRow(newExpander, row);
only sets Grid.Row="1" if row is 1 in your object properties.
To use this properties the grid that contains the object must have it's RowDefinitions set
How can you tell it which grid you want to set the new row for if you have multiple grids in the .xaml code?
You don't need to tell since the object remains in the Grid in witch you added it.
When you change the Property Grid.Row it only sets on witch row of the grid, your control will be rendered
Related
I am making a Gridview that scrolls behind a title element (which is semi transparent to show the items being scrolled behind it). To do this, I have layered the Grid containing the title and the GridView by placing them both as children in the same Grid.
<Grid>
<GridView>
<!-- Stuff -->
<GridView>
<Grid Height="100">
<!-- Title Content here -->
</Grid>
</Grid>
This works fine, but causes the GridView to display elements initially behind the title. To fix this, I offset the ItemsWrapGrid in the GridView:
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid Name="ItemsWrapGrid"
Margin="0,100,0,0"
Orientation="Horizontal"
HorizontalAlignment="Center"></ItemsWrapGrid>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
Now the items start as if they are below the title content, and scroll underneath it.
The only remaining problem is the scrollbar for the GridView. The scrollbar still goes to the top of the parent Grid, which means it goes behind the title, even though the items in the GridView themselves begin below the title. This is particularly an issue when there are enough items in the GridView (rows) to cause the scrollbar to be small enough that it is entirely behind the title.
Is there a way to offset the scrollbar similar to the GridView items? Is this the wrong approach?
UWP Offset GridView Scrollbar
For your requirement, you could use VisualTreeHelper to get VerticalScrollBar element, then set Margin = 0,100,0,0 in the GridView load event handler. For detail steps please refer the following code.
public static DependencyObject MyFindGridViewChildByName(DependencyObject parant, string ControlName)
{
int count = VisualTreeHelper.GetChildrenCount(parant);
for (int i = 0; i < count; i++)
{
var MyChild = VisualTreeHelper.GetChild(parant, i);
if (MyChild is FrameworkElement && ((FrameworkElement)MyChild).Name == ControlName)
return MyChild;
var FindResult = MyFindGridViewChildByName(MyChild, ControlName);
if (FindResult != null)
return FindResult;
}
return null;
}
private void TestGridView_Loaded(object sender, RoutedEventArgs e)
{
var scrollBar = MyFindGridViewChildByName(TestGridView, "VerticalScrollBar");
scrollBar.SetValue(MarginProperty, new Thickness(0, 100, 0, 0));
}
Simpel question, I have a windows phone page that contains a scrollviewer with inside it an image, a textblock and a richtextbox.
Now when the user starts scrolling I want to keep the textblock in view on top when the image has scrolled outside the page.
So the effect is, user starts scrolling upwards, everything scrolls upwards, when the image is outside the page, the textblock stays at the top of the page but the richtextbox keeps scrolling upwards.
Any thoughts?
Here is a way to reach this result:
First, the layout. I've set a grid, with two rows. The first is empty, and will host the header when we need to freeze it. The second row contains the scrollviewer.
Inside the scrollviewer, I've put the controls in a grid, but you can use whatever container suits you.
<ScrollViewer Grid.Row="1"
Margin="0"
Padding="0"
x:Name="ParentScroll"
ManipulationMode="Control"
MouseMove="ParentScroll_MouseMove">
<Grid x:Name="ChildGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Image Source="Picture.jpg" Grid.Row="0"/>
<TextBlock Text="Header" Grid.Row="1" x:Name="TextHeader" />
<RichTextBox Grid.Row="2" x:Name="RichText">
<Paragraph>
<Bold>RichTextBox</Bold>
<!-- More stuff -->
</Paragraph>
</RichTextBox>
</Grid>
</ScrollViewer>
I use the MouseMove event to be notified of the scrolling event. You can also dig into the template, extract the ScrollBar control, and subscribe to the ValueChanged event, as described here: http://social.msdn.microsoft.com/Forums/wpapps/en-US/81fcd34e-6ec9-48d0-891e-c53a53344553/scrollviewer-synchronization
Note that you need to set ManipulationMode to Control or the position of the controls won't be updated at a smooth rate. I guess it's due to some internal optimization.
In the code behind, I use the TransformToVisual method to compute the relative position of the controls to the ScrollViewer. This way, I can know when the header goes out of view. When it does, I remove it from the child grid, and put it outside of the ScrollViewer, in the parent grid. When the top of the RichTextBox goes out of view, I put the header back into the ScrollViewer:
private void ParentScroll_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (Grid.GetRow(this.TextHeader) == 1)
{
var generalTransform = TextHeader.TransformToVisual(ParentScroll);
var childToParentCoordinates = generalTransform.Transform(new Point(0, 0));
if (childToParentCoordinates.Y < 0)
{
this.ChildGrid.Children.Remove(this.TextHeader);
this.ParentGrid.Children.Add(this.TextHeader);
Grid.SetRow(this.TextHeader, 0);
}
}
else
{
var generalTransform = RichText.TransformToVisual(ParentScroll);
var childToParentCoordinates = generalTransform.Transform(new Point(0, 0));
if (childToParentCoordinates.Y > 0)
{
this.ParentGrid.Children.Remove(this.TextHeader);
this.ChildGrid.Children.Add(this.TextHeader);
Grid.SetRow(this.TextHeader, 1);
}
}
There may be less-hacky ways to reach the same results, but this solution seems to work smoothly in the emulator.
I've found a working solution myself... the complete detail is available on my blog here... it contains also the link to my demo project on GitHub.
The trick was to get hold of the VerticallScrollBar inside the ScrollViewer and to set the ManipulationMode to Control to get enough feedback on the UI thread.
With the scroll offset information of the scrollbar we than animate the specific ui element we want to keep in view.
I am displaying the items in grid view .I want to show the grid view items in another page using flip view control.How to dynamically display the selected item position in second page ?
Please tell me how to achieve this?
EDIT:
In First Page :
Grid View item click event i wrote code like this:
private void PhotoGrid_ItemClick(object sender, ItemClickEventArgs e)
{
var itemid = ((flipimage)e.ClickedItem);
flipimage s = new flipimage() { ImageUrl = itemid.ImageUrl, Title = itemid.Title };
this.Frame.Navigate(typeof(FlipPage), s);
}
In Second Page:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
flipimage s = (flipimage)e.Parameter;
string url = s.ImageUrl;
flipviewcontrol.Items.Add(url);
}
I want to display previous page selected item in second page and also click on next in flipview need to show after that selected item data.Please tell me how to write the code.
For data binding to
flipview :
XDocument xdoc = XDocument.Load("XMLFile1.xml");
IEnumerable<flipimage> images = from img in xdoc.Descendants("Image") select new flipimage(img.Element("ImageTitle").Value, img.Element("ImageUrl").Value);
flipviewcontrol.DataContext = images;
Design of Flipview:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<FlipView HorizontalAlignment="Left" VerticalAlignment="Top" x:Name="flipviewcontrol" ItemsSource="{Binding}">
<FlipView.ItemTemplate>
<DataTemplate>
<Image HorizontalAlignment="Left" Source="{Binding ImageUrl}" Height="762" VerticalAlignment="Top" Width="1360" x:Name="imagecontrol"/>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
</Grid>
Please tell me how to show previous page selected item value and when click on next in filpview need to show after selected items data of the page vice versa!!!
I'm trying to load a listbox with a list of items being pulled from an OData web service. The data fetch is working well and I'm getting the list of items. The listbox actually works and displays the items, just not every time I start the application... Due to the requirement for the data to be pulled asynchronously sometimes the listbox loads up before the data has returned. When it does I feed it a list with a single 'empty' item to indicate that the data is still loading. Seconds later the data has loaded and I raise a PropertyChanged event for the list. My breakpoint in the list property triggers and when I check the list contains the correct items. But the listbox doesn't display the new items, only the old 'empty' item. It seems exceptionally odd to me that the xaml is clearly requesting the list but then doesn't refresh the layout for the new items.
First the code initialising the ViewModel. ModelReferenceMap implements INotifyPropertyChanged and so should be updating the view when OnPropertyChanged("Areas"); is called (this triggers a fetch of the list from the property but doesn't update the view).
public ModelReferenceMap(Uri serviceURI)
{
// Try initialising these lists to a non null but empty list
// in the hope it will stop the lists breaking when the service
// is a little bit slow...
areas = new List<ModelReferenceItem> { new ModelReferenceItem(null) };
// This is a ServiceReference entity context which will retrieve the data from the OData service
context = new LiveEntities(serviceURI);
// SendingRequest adds credentials for the web service
context.SendingRequest += context_SendingRequest;
// The query to retrieve the items
var areaQuery = from i in context.MigrationItems where i.FusionPTID == 0 && i.Type == "AreaType" orderby i.Name select i;
// On completion this asynccallback is called
AsyncCallback ac = iasyncResult =>
{
// Populates the List with the data items
areas = (from i in ((DataServiceQuery<MigrationItem>) areaQuery).EndExecute(iasyncResult)
select new ModelReferenceItem(i)).ToList();
foreach (ModelReferenceItem area in areas)
{
if (selectedArea == null)
selectedArea = area;
area.PropertyChanged += referenceItem_PropertyChanged;
}
// The Xaml Listbox has its ItemsSource bound to the Areas property. This should trigger a refresh of the listbox contents shouldn't it?
OnPropertyChanged("Areas");
OnPropertyChanged("SelectedArea");
};
// Start the query
((DataServiceQuery<MigrationItem>)areaQuery).BeginExecute(ac, null);
}
Now the XAML. Note that the DataContext of the listbox is ReferenceMap (a property on my main ViewModel which exposes a singleton instance of ModelReferenceMap). I've then bound the ItemsSource to Areas.
<ListBox Grid.Row="0" DataContext="{Binding ReferenceMap}" ItemsSource="{Binding Areas}" SelectedItem="{Binding SelectedArea, Mode=TwoWay}" HorizontalAlignment="Stretch" Margin="3" Name="listBoxFusionAreas" VerticalAlignment="Stretch">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Background="{Binding CompleteStatusColour}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock FontSize="12" Text="{Binding Name}" />
<TextBlock Grid.Column="1" FontSize="12" Text="{Binding Count}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The Areas property is triggering correctly indicating the binding is working. When Areas is only requested AFTER the service data has been retrieved (ie only once) the list works perfectly. If however the Areas property is triggered prior to the service data returning (ie with the single 'empty' item) it triggers again during the OnPropertyChanged("Areas"); call with the full set of items, only this time the list still just shows the original 'empty' item.
What am I doing wrong?
Whenever you are binding to a collection in your ViewModel you need to make sure whether the items in your collection are gonna change?? In your case you need to implement
ObservableCollection<ModelReferenceItem> areas ;
Instead of
List<ModelReferenceItem> area;
ObservableCollection implements INoifyCollectionChanged event that notifies your view about the changes in the collection (Add/Remove)
In a typical Master/Detail situation...
I have a DataGrid. The ItemsSource of this DataGrid is set in the Completed event of a WCF call - (grdMaster.ItemsSource = e.Result) - where the x:Name of the grid is grdMaster. This is all 100%.
However, when adding a Detail Datagrid inside the master grids DataTemplate and naming it appropriately... my codebehind does not recognise the detail grid. So plainly put, I cannot set the ItemsSource of grdDetail like I do with grdMaster.
Depending on the Master item selected, I need to do a WCF call to get the appropriate Details.
Depending on how you are being notified that an item is being selected for expansion you will need to find the row the user is in:
DataGridRow row = DataGridRow.GetRowContainingElement(...);
and update the row details visibility:
row.DetailsVisibility = Visibility.Visible;
Those details aside, you need to create a style for the details rows -- which is wired to an event you can listen to:
<DataTemplate x:Key="DetailsRowTemplate">
<StackPanel>
<Border BorderBrush="{StaticResource BlackBrush}" BorderThickness="0,2,0,0" Padding="0" >
<data:DataGrid ItemsSource="{Binding DummyResultsView}" AutoGenerateColumns="False"
LoadingRow="DataGrid_LoadingRow"
CanUserResizeColumns="False"
CanUserReorderColumns="False"
HeadersVisibility="None"
IsReadOnly="True">
</data:DataGrid>
</Border>
</StackPanel>
</DataTemplate>
which is set as the RowDetailsTemplate for your grid:
Within the LoadingRow event you can obtain a reference to which data context is involved, and save a reference to the child data grid so that after a WCF call you can set the ItemsSource:
private void DataGrid_LoadingRowDetails(object sender, DataGridRowDetailsEventArgs e)
{
List<DataGrid> detailElements = e.DetailsElement.GetChildrenByType<System.Windows.Controls.DataGrid>().ToList();
var itemSelected = e.Row.DataContext;
if (detailElements.Count > 0)
{
DataGrid detailsDataGrid = detailElements[0];
// save a reference so the ItemsSource can be set later....
this.DataGrid = detailsDataGrid;
this.Model.InitializeDetailsList(detailsDataGrid, itemSelected);
}
}
Hope that helps,