First of all I am new to UWP and I have already searched almost everywhere (using Google and Stackoverflow) for the answer but couldn't find the answer for my problem.
So, Here is the problem:
I planned to create a pixel paint app that has tab function like Edge (utilizing title bar) for UWP using Visual Studio 2017 and Target Sdk: Creators Update.
I wanted to move the custom title bar I made to the content view when the app in fullscreen condition.
I wanted to move from here (windows title bar, this is just the button XAML code, I'm not including the tab bar XAML code because it's a commercial project):
<Grid x:Name="btnMenuPlace1" Grid.Column="0">
<Grid x:Name="btnMenuPlaceContent" Background="{StaticResource SystemControlHighlightListAccentMediumBrush}">
<Button x:Name="btnMenu" FontFamily="Segoe MDL2 Assets" Content=""
Width="50" Height="50" Background="Transparent" Click="btnMenu_Click"/>
</Grid>
</Grid>
To here (user view):
<Grid x:Name="btnMenuPlace2" Grid.Column="0">
</Grid>
Both parent of those Grid is an another Grid using Grid.ColumnDefinitions like this:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
And here's my C# Code:
private void WindowSizeChanged(object sender, WindowSizeChangedEventArgs e)
{
var appView = ApplicationView.GetForCurrentView();
if (appView.IsFullScreenMode)
{
Utility.RemoveChild(btnMenuPlaceContent);
btnMenuPlace2.Children.Add(btnMenuPlaceContent);
Utility.RemoveChild(tabBarPlaceContent);
tabBarPlace2.Children.Add(tabBarPlaceContent);
}
else
{
Utility.RemoveChild(btnMenuPlaceContent);
btnMenuPlace1.Children.Add(btnMenuPlaceContent);
Utility.RemoveChild(tabBarPlaceContent);
tabBarPlace1.Children.Add(tabBarPlaceContent);
}
e.Handled = true;
}
And here is my Utility RemoveChild Code:
public static void RemoveChild(DependencyObject parent, UIElement child)
{
var parentAsPanel = VisualTreeHelper.GetParent(child);
if (parentAsPanel != null)
{
parentAsPanel.Children.Remove(child);
return;
}
var parentAsContentPresenter = parent as ContentPresenter;
if (parentAsContentPresenter != null)
{
if (parentAsContentPresenter.Content == child)
{
parentAsContentPresenter.Content = null;
}
return;
}
var parentAsContentControl = parent as ContentControl;
if (parentAsContentControl != null)
{
if (parentAsContentControl.Content == child)
{
parentAsContentControl.Content = null;
}
return;
}
}
This is my app looks like before entered the fullscreen mode:
So the problem is whenever the app entered the fullscreen mode, the child does move to the new parent, but the button is not there only the background color of the grid remaining and I can't click any of them (not a single click event work), take a look:
And when I switched back to not fullscreen view the proggressbar loading on the new tab not shown.
I don't know which one I did was wrong XAML or the C# code.
Any help would be appreciated.
P.S. I'm Indonesian, so maybe there is something wrong with my sentence, hopefully You are understand what I'm talking about.
There are somethings wrong with your code snippet. For example, RemoveChild method has two parameters but you only provide one when you invoking it. And without assign the parentAsPanel variable type, you cannot get the Children property.
Since the code is not completed, after code updated and add some other code needed I can run your code snippet correctly and cannot reproduce the issue above. Here is my completed testing code:
XAML
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<Grid x:Name="btnMenuPlace1" Grid.Column="0" Grid.Row="0">
<Grid x:Name="btnMenuPlaceContent" Background="{StaticResource SystemControlHighlightListAccentMediumBrush}">
<StackPanel Orientation="Horizontal">
<Button x:Name="btnMenu" FontFamily="Segoe MDL2 Assets" Content="" Width="50" Height="50" Background="Transparent" />
<!--<local:CustomTitleBar Width="200" Height="50"></local:CustomTitleBar>-->
</StackPanel>
</Grid>
</Grid>
<Grid x:Name="btnMenuPlace2" Grid.Column="1" Grid.Row="1"/>
<TextBlock Text="text" x:Name="txtresult"></TextBlock>
<Button x:Name="ToggleFullScreenModeButton" Margin="0,10,0,0" Click="ToggleFullScreenModeButton_Click">
<SymbolIcon x:Name="ToggleFullScreenModeSymbol" Symbol="FullScreen" />
</Button>
</StackPanel>
</Grid>
Code behind
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
Window.Current.SetTitleBar(btnMenuPlace1);
Window.Current.SizeChanged += Current_SizeChanged;
}
private void Current_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
var appView = ApplicationView.GetForCurrentView();
if (appView.IsFullScreenMode)
{
RemoveChild(btnMenuPlace1, btnMenuPlaceContent);
btnMenuPlace2.Children.Add(btnMenuPlaceContent);
}
else
{
RemoveChild(btnMenuPlace2, btnMenuPlaceContent);
btnMenuPlace1.Children.Add(btnMenuPlaceContent);
}
e.Handled = true;
}
public void RemoveChild(DependencyObject parent, UIElement child)
{
Grid parentAsPanel = VisualTreeHelper.GetParent(child) as Grid;
if (parentAsPanel != null)
{
parentAsPanel.Children.Remove(child);
return;
}
var parentAsContentPresenter = parent as ContentPresenter;
if (parentAsContentPresenter != null)
{
if (parentAsContentPresenter.Content == child)
{
parentAsContentPresenter.Content = null;
}
return;
}
var parentAsContentControl = parent as ContentControl;
if (parentAsContentControl != null)
{
if (parentAsContentControl.Content == child)
{
parentAsContentControl.Content = null;
}
return;
}
}
private void ToggleFullScreenModeButton_Click(object sender, RoutedEventArgs e)
{
var view = ApplicationView.GetForCurrentView();
if (view.IsFullScreenMode)
{
view.ExitFullScreenMode();
}
else
{
if (view.TryEnterFullScreenMode())
{
txtresult.Text = "full screen";
}
else
{
txtresult.Text = "no full screen";
}
}
}
}
My testing environment is OS build 15063. If you still have issues please provide the minimal reproduced project. You may just try to reproduce the issue on my testing demo. More details please reference the official sample.
Sorry it was My mistake, that above code I post is actually working (just some of the code wrongly copied, like for example the parameter on the utility code is not necessary).
The false is on it's parent, i forgot to add row definition on the second place (btnPlace2) parent.
Now it works and looks great now :)
Here is some picture of em:
On FullScreen Mode:
Thanks to anyone answering and voting this question up.
Best regards,
andr33ww
Related
I'm working with an item template that should display one or more buttons per item. There are three buttons that I want to be displayed on a horizontal line. Each button has an icon and some text.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="LeftButton"
Text="Left Button"
ImageSource="left.png"
HorizontalOptions="Start"/>
<Button x:Name="CenterButton"
Text="Center Button"
ImageSource="center.png"
HorizontalOptions="Center"/>
<Button x:Name="RightButton"
Text="Right Button"
ImageSource="right.png"
HorizontalOptions="End"/>
</Grid>
This is working good so far. The three buttons display the icon and text and they are aligned left, center and right respectively.
Now, I want the buttons to only display the icons, if the container is not wide enough to display all the text. As far as I understand MVVM, this should be the responsibility of the View.
My intended solution would be something like this:
public partial class ItemTemplate : ContentView
// ContentView is our implementation of a UI element.
{
public ItempTemplate()
{
InitializeComponent();
SizeChanged += HandleSizeChanged;
}
private void HandleSizeChanged(object sender, EventArgs e)
{
if (/* not enough space */)
{
LeftButton.Text = string.Empty;
CenterButton.Text = string.Empty;
RightButton.Text = string.Empty;
}
else
{
LeftButton.Text = "Left Button";
CenterButton.Text = "Center Button";
RightButton.Text = "Right Button";
}
}
}
Is there any way to know if the container is wide enough for all three button? If possible, I'd like to use a dynamic solution, because the button text will eventually be translated.
You can place the code into a custom contentview , and decide to hide/show the text in the event LayoutChanged according to the container's width .
Custom View xaml
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="LeftButton" Grid.Column="0" Text="Left Button" ImageSource="dots.png" HorizontalOptions="Start"/>
<Button x:Name="CenterButton" Grid.Column="1" Text="Center Button" ImageSource="dots.png" HorizontalOptions="Center"/>
<Button x:Name="RightButton" Grid.Column="2" Text="Right Button" ImageSource="dots.png" HorizontalOptions="End"/>
</Grid>
Custom View code behind
public partial class MyView : ContentView
{
public MyView()
{
InitializeComponent();
this.LayoutChanged += MyView_LayoutChanged;
}
private void MyView_LayoutChanged(object sender, EventArgs e)
{
var view = sender as View;
if (view.Width < 200)
{
LeftButton.Text = string.Empty;
CenterButton.Text = string.Empty;
RightButton.Text = string.Empty;
}
else
{
LeftButton.Text = "Left Button";
CenterButton.Text = "Center Button";
RightButton.Text = "Right Button";
}
}
}
Scenario : container is large enough.
xmlns:local="clr-namespace:FormsApp"
<local:MyView/>
Scenario : container is small ,wrapped inside another layout .
<Grid HorizontalOptions="Start" WidthRequest="199" >
<local:MyView/>
</Grid>
I solved my problem by using a custom button implementation (mostly because I needed some other additional features).
The custom button contains an Image and a Label. In addition to the standard button features I need, I added these methods to the code-behind:
public void ExpandText() {
Label.IsVisible = true;
}
public void CollapseText() {
Label.IsVisible = false;
}
public bool IsTextCollapsed() {
return !Label.IsVisible;
}
public double GetWidthAsExpanded() {
return Image.Width + Label.Width;
}
In the container's code-behind I check if the button's width fits within its container and collapse/expand accordingly. For that to work, I added containers for each button.
public ItemTemplate() {
InitializeComponent();
LayoutChanged += HandleLayoutChanged;
}
private static void HandleLayoutChanged(object sender, EventArgs e)
{
if (!(sender is ItemTemplate itemTemplate))
{
return;
}
if (itemTemplate.ButtonContainerLeft.Width > itemTemplate.ButtonLeft.GetWidthAsExpanded()
&& itemTemplate.ButtonContainerCenter.Width > itemTemplate.ButtonCenter.GetWidthAsExpanded()
&& itemTemplate.ButtonContainerRight.Width > itemTemplate.ButtonRight.GetWidthAsExpanded())
{
ExpandAllButtons(itemTemplate);
}
else
{
CollapseAllButtons(itemTemplate);
}
}
Because I added ExpandText and CollapseText earlier, I don't have to "remember" what the text inside the button was, because I just collapse the label within the button. GetWidthAsExpanded will always return the necessary width of the button, even if it is collapsed.
side-note 1: I could've just added the width-check within the custom button implementation, but not every ItemTemplate has all buttons and if any label is collapsed, all labels should be collapsed.
side-note 2: I needed button containers either way, because the left button will either be "Mark as Read" or "Mark as Unread" depending on the state of the ItemTemplate data context. So there are actually two buttons in the first container.
I have a Universal Windows Application for a local bank, I'm working on a money transfer view, and they need to transfer money from account to account using the Drag and Drop feature in UWP applications.
I've made the animation part, but I need help after I drop the list item to the "Account To" list.
I'll attach a screenshot to make it clear.
As you see in the picture, I need to drag one item from the "From Account" list and drop it on only one item on "To Account" list. How can I achieve this ?
I've created a small sample which shows drag-drop between two ListViews filled with some Accounts. I will skip the implementation of UserControls - the Page xaml looks like this:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="200"/>
<RowDefinition Height="200"/>
</Grid.RowDefinitions>
<ListView Header="Source" Margin="10" Grid.Row="0" CanDragItems="True" ItemsSource="{x:Bind Accounts}" SelectionMode="None">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<controls:AccountControl CanDrag="True" DragStarting="AccountControl_DragStarting"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView Header="Targets" Margin="10" Grid.Row="1" ItemsSource="{x:Bind Accounts}" SelectionMode="None">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<controls:AccountControl AllowDrop="True" DragEnter="AccountControl_DragEnter" Drop="AccountControl_Drop"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
As you can see there is a Source list in which the control is firing an event when it's being dragged.
private void AccountControl_DragStarting(UIElement sender, DragStartingEventArgs args)
{
if ((sender as AccountControl)?.DataContext is Account account)
{
args.AllowedOperations = DataPackageOperation.Link;
args.Data.SetData(accountId, account.Id);
}
}
The Account class apart from name and balance has a Guid identifier so I can use it to pass information which source account has been used in transfer method.
The items in second list (Targets) accepts only drop operation and for this purpose fire two events:
private void AccountControl_DragEnter(object sender, DragEventArgs e)
{
e.AcceptedOperation = DataPackageOperation.Link;
e.DragUIOverride.Caption = "Transfer";
}
private async void AccountControl_Drop(object sender, DragEventArgs e)
{
if ((e.OriginalSource as AccountControl)?.DataContext is Account targetAccount)
if (await (e.DataView.GetDataAsync(accountId)) is Guid sourceAccountId)
{
var sourceAccount = Accounts.First(x => x.Id == sourceAccountId);
sourceAccount.Balance -= 1000;
targetAccount.Balance += 1000;
}
}
The first one sets accepted operation and some information for the user. The second one 'transfers' some money from one account to the second.
Everything looks like this:
Some more help you can find at MS directly, other article and in MS samples repository.
I am not fully satisfied with the "solutions" which I will provide. They are much likely very far away from the ideal implementations, but ...
The XAML code which I created to try to replicate as easily, but also consistently your object, consisted in a group of draggable Rectangles inside a StackPanel Control, plus another StackPanel Control where the items could be dragged into.
<Grid>
<Grid.Resources>
<Style TargetType="Rectangle">
<Setter Property="Width" Value="300"/>
<Setter Property="Height" Value="300"/>
<Setter Property="CanDrag" Value="True"/>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Name="StackPanelRectangles" Grid.Row="0" Orientation="Horizontal">
<Rectangle x:Name="RedRect" Fill="Red" DragStarting="Rectangle_DragStarting"/>
<Rectangle x:Name="GreenRect" Fill="Green" DragStarting="Rectangle_DragStarting"/>
<Rectangle x:Name="BlueRect" Fill="Blue" DragStarting="Rectangle_DragStarting"/>
</StackPanel>
<StackPanel Name="StackPanelDropArea" Background="Azure" AllowDrop="True"
DragOver="StackPanel_DragOver" Drop="StackPanel_Drop"
Grid.Row="2" Orientation="Horizontal"
HorizontalAlignment="Center">
<TextBlock>Drop anywhere in this area area</TextBlock>
</StackPanel>
</Grid>
1st Solution:
I routed every DragStarting event of the multiple Rectangles to the same EventHandler. In this EventHandler, we have access to the UIElement which is being dragged, so with an exposed property of type UIElement in your Page class, and you can simply clone the necessary properties for when you need to drop it, like this:
UIElement dragItem;
private void Rectangle_DragStarting(UIElement sender, DragStartingEventArgs args)
{
dataPackage.RequestedOperation = DataPackageOperation.Copy;
dragItem = sender;
}
Then when the item is dropped EventHandler is called, I have simply add it onto my DropArea.
private void StackPanel_Drop(object sender, DragEventArgs e)
{
Rectangle newElement = new Rectangle();
newElement.Width = (dragItem as Rectangle).Width;
newElement.Height = (dragItem as Rectangle).Height;
newElement.Fill = (dragItem as Rectangle).Fill;
StackPanelDropArea.Children.Add(newElement);
}
You cannot add your new Control by setting to reference the object being dragged, since there are properties such as the respective Parent which will thrown an exception when you try to add the Control to a different container.
2nd Solution:
I was extremely focused on on utilizing the DataPackage object, and one of its supported default formats, but I don't think any of them can actually hold data of an Object, such as our UIElement.
But each DataPackage instance supports a set of properties, which corresponds a Dictionary. We can set the Dictionary to hold UIElement in there, as long as we specify a key to reference that same object later on.
private void Rectangle_DragStarting(UIElement sender, DragStartingEventArgs args)
{
dataPackage.RequestedOperation = DataPackageOperation.Copy;
args.Data.Properties.Add("myRectangle", sender);
}
In the drop Event Handler, you can obtain the UIElement, like such:
private async void StackPanel_Drop(object sender, DragEventArgs e)
{
Rectangle element = e.DataView.Properties["myRectangle"] as Rectangle;
......
......
}
3rd Solution:
This solution used the method SetText(String) exposed by DataPackage, to hold the value of the Name property of the UIElement being dragged.
private void Rectangle_DragStarting(UIElement sender, DragStartingEventArgs args)
{
dataPackage = new DataPackage();
dataPackage.RequestedOperation = DataPackageOperation.Copy;
Rectangle rectangle = sender as Rectangle;
dataPackage.SetText(rectangle.Name);
Clipboard.SetContent(dataPackage);
}
By knowing the value of the Name property of the UIElement which is being dragged, looked for it, by using the VisualTreeHelper Class, like this:
private async void StackPanel_Drop(object sender, DragEventArgs e)
{
DataPackageView dataPackageView = Clipboard.GetContent();
if (dataPackageView.Contains(StandardDataFormats.Text))
{
draggedObject = await dataPackageView.GetTextAsync();
}
// Dragged objects come from another one of our Parent's Children
DependencyObject parent = VisualTreeHelper.GetParent(StackPanelDropArea);
int count = VisualTreeHelper.GetChildrenCount(parent);
for(int i=0; i< count; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
if(child.GetType().Equals(typeof(StackPanel)))
{
StackPanel currentStackPanel = child as StackPanel;
if(currentStackPanel.Name == "StackPanelRectangles")
{
int numberOfRectangles = VisualTreeHelper.GetChildrenCount(currentStackPanel);
for(int j=0; j<numberOfRectangles; j++)
{
if(VisualTreeHelper.GetChild(currentStackPanel,j).GetType().Equals(typeof(Rectangle)))
{
Rectangle currentRectangle = VisualTreeHelper.GetChild(currentStackPanel, j) as Rectangle;
if (draggedObject != string.Empty && currentRectangle.Name.Equals(draggedObject))
{
Rectangle newRectangle = new Rectangle();
newRectangle.Width = currentRectangle.Width;
newRectangle.Height = currentRectangle.Height;
newRectangle.Fill = currentRectangle.Fill;
StackPanelDropArea.Children.Add(newRectangle);
}
}
}
}
}
} */
}
Result:
I usually try tackling this several times before giving up and using a third party library. The one I typically use is:
https://github.com/punker76/gong-wpf-dragdrop
You may subscribe to PointerPressed event in your DataTemplate and extract all the things you need.
XAML:
<DataTemplate x:Name="DataTemplate">
<Grid Background="Transparent" PointerPressed="Grid_OnPointerPressed"/>
</DataTemplate>
Code:
private void Grid_OnPointerPressed(object sender, PointerRoutedEventArgs e)
{
//your FrameworkElement
var frameworkElement = sender as FrameworkElement;
//global position of your element
var itemPosition = frameworkElement.TransformToVisual(Window.Current.Content).TransformPoint(new Point(0, 0)).ToVector2();
//your data
var selectedItemData = frameworkElement.DataContext as ItemData;
}
Save your data, use UWP Drag'n'Drop. On drop load your data.
i want to Know the x:Name of the Grid child as in this case :
<Grid x:Name="one" Grid.Row="0" Margin="49.667,15,15,15">
<Grid x:Name="container1" Background="Red" Margin="10"/>
</Grid>
<Button Content="mov" Foreground="White" x:Name="first" HorizontalAlignment="Left" Margin="8,44.833,0,70.167" Width="29.334" Background="Black" Click="first_Click"/>
and here the code when i click :
private void first_Click(object sender, System.Windows.RoutedEventArgs e)
{
var ttt = FindVisualChild<Grid>(one);
MessageBox.Show(ttt.ToString());
}
private static T FindVisualChild<T>(DependencyObject parent) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
if (child != null && child is T)
return (T)child;
else
{
T childOfChild = FindVisualChild<T>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
When i click the message just show this content "System.Window.Controls.Grid" instead i want to know the x:name in this case "container1" then i ask kindly if you have any suggestion that i can receive the x:Name of the Grid.
Thank you in advance.
Sincerely
Credit goes to dkozl for providing you the answer in the comments of the OP. I wanted to give a bit of additional information to supplement it.
Any element that is exposed to you within the XAML can be accessed in the code-behind as a property (there are some exceptions but for the most part this rings true).
<Grid x:Name="one" Grid.Row="0" Margin="49.667,15,15,15">
<Grid x:Name="container1" Background="Red" Margin="10"/>
</Grid>
<Button Content="mov" Foreground="White" x:Name="first" HorizontalAlignment="Left" Margin="8,44.833,0,70.167" Width="29.334" Background="Black" Click="first_Click"/>
If you wanted to, you can access the Grid properties like
private void first_Click(object sender, System.Windows.RoutedEventArgs e)
{
this.one.Background = Brushes.Yellow;
this.one.Margin = new Thickness(0, 5, 10, 25);
}
You also do not need to use the visual tree lookup since you have provided a name to the grid, providing the code-behind is associated with the view that holds the two grids.
You can just do:
private void first_Click(object sender, System.Windows.RoutedEventArgs e)
{
MessageBox.Show(this.container1.Name);
}
I have a UserControl that I instantiate in code behind and would like to print. When I print this UserControl the code prints a blank piece of paper. Why is this? My code is as follows
private void PrintCurrentTab(object sender, RoutedEventArgs e)
{
PrintDialog printDlg = new PrintDialog();
var child = MyMainWindowViewModel.SelectedTab.Content;
if (child is ScrollViewer)
{
child = (((ScrollViewer)child).Content);
}
if (printDlg.ShowDialog() == true)
{
var printControl = new PrintingTemplate();
printDlg.PrintVisual(printControl, "User Control Printing.");
}
}
My UserControl is as follows
<UserControl x:Class="MyApp.Views.PrintingTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
MinHeight="500"
MaxHeight="1000"
MinWidth="200"
MaxWidth="1000"
Height="1056"
Width="816">
<StackPanel>
<Grid>
<Image Source="..\Resources\Images\PrintLogo.jpg" Width="150" HorizontalAlignment="Right" Margin="20"/>
<Rectangle Fill="Black" Margin="10,40,150,0" Height="2"/>
</Grid>
<Grid Name="PrintingGrid"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Label Content="Printed By:"/>
<Label Name="PrintedBy"/>
<Label Content="Printed On:"/>
<Label Name="PrintedDate"/>
</StackPanel>
</StackPanel>
</UserControl>
I got a similar problem where I was able to print from some computers but not from one (only blank page), on a physical printer (working OK with XPS). I finally got a working solution here:
» https://social.msdn.microsoft.com/Forums/vstudio/en-US/9eb79e11-ee5a-4687-ad4c-a6d96276a8f4/printing-a-wpf-usercontrol?forum=wpf
UserControlToPrint.Measure(New Size(816, 1056))
UserControlToPrint.Arrange(New Rect(New Size(816, 1056)))
UserControlToPrint.UpdateLayout()
Regards,
François from Québec
perhaps the new in the following code is the culprit
if (printDlg.ShowDialog() == true)
{
var printControl = new PrintingTemplate();
printDlg.PrintVisual(printControl, "User Control Printing.");
}
try to get the handle to the current control rather than create a new
Have you debugged this at all? Your question seems incomplete, and I don't really know what you're trying to accomplish. I DO notice that an important step is missing. Here are some questions I have though:
Is MyMainWindowViewModel.SelectedTab.Content == null?
What is child's type?
What is the purpose of child = (((ScrollViewer)child).Content);--that's ugly
Actually why is any of the child code in there, its not being used!
Anyways, you can't print a control that hasn't gone through a layout pass. So now you might ask, "how do I force a control to be rendered?" Simple, like this:
if (printDlg.ShowDialog() == true)
{
var printableArea = new Size(printDlg.PrintableAreaWidth, printDlg.PrintableAreaHeight)
var printControl = new PrintingTemplate();
//Set the drawing dimensions/boundaries - notice (Acutal)Width/Height = 0
printControl.Measure(printableArea);
printControl.Arrange(new Rect(new Point(), printableArea);
//"Render"!
printcontrol.UpdateLayout();
//At this point you should see the (Acutal)Width/Height be > 0!
printDlg.PrintVisual(printControl, "User Control Printing.");
}
I am a new developer on Windows Phone 8.1, I am try to reach a specific ListView item from the ListView collection and be able to color it or color the TextBock inside of it, But I can't reach the item or reach any of items inside of ListView, Please take a look for my below code :
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
SQLiteRT db1 = new SQLiteRT();
var db_connection = await db1.Connection("MyDB.sqlite");
List<MyTBL> t_list = db1.GetTable("SELECT * FROM MyTBL LIMIT 4 ORDER BY RANDOM() ;");
db_connection.Close();
LV_Options.ItemsSource = t_list;
}
// my List View called LV_Options
private void LV_Options_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListView lv1 = sender as ListView;
if (lv1 == null)
return;
MyTBL wrd = lv1.SelectedItem as MyTBL;
if (wrd == null)
return;
TextBlock tb = lv1.FindName("TB_AMean1") as TextBlock;
tb.FontSize = 17; // here I got debug error (it not worked !!!!!!!)
var item = LV_Options.Items.ElementAt(3); // this seems not work also !!!!
item.BackColor = Color.LightSteelBlue;
}
As you can see above, I tried to reach a specific item by LV_Options.Items.ElementAt(3) but it doesn't work! I also tried to reach the TextBlock from the selected List view item, but also not worked !
(Updated)
XAML code :
<!-- Title Panel -->
<StackPanel Grid.Row="0" Margin="19,0,0,0">
<TextBlock Name="TB_Rslt" Text="Here result of your answer" Style="{ThemeResource TitleTextBlockStyle}" Margin="0,12,0,0"/>
<TextBlock Text="page title" Margin="0,-6.5,0,26.5" Style="{ThemeResource HeaderTextBlockStyle}" CharacterSpacing="{ThemeResource PivotHeaderItemCharacterSpacing}"/>
</StackPanel>
<!--TODO: Content should be placed within the following grid-->
<Grid Grid.Row="1" x:Name="ContentRoot" Margin="19,10,19,15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Name="TB_Question" Text="Choose Answer " Margin="0,0,25,0" HorizontalAlignment="Right" FontWeight="Bold" FontSize="22" FontFamily="Verdana" RenderTransformOrigin="0.5,0.5" />
<TextBlock Name="TB_EnWord" Text="" Margin="90,0,15,0" HorizontalAlignment="Left" FontWeight="Bold" FontSize="22" FontFamily="Verdana" RenderTransformOrigin="0.5,0.5" TextAlignment="Right" />
<StackPanel Grid.Row="1" Margin="5,22,0,0">
<ListView Name="LV_Options" SelectionChanged="LV_Options_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="6">
<StackPanel VerticalAlignment="Top" Margin="10,0,0,0">
<TextBlock Name="TB_AMean1" Text="{Binding AMean1}" TextWrapping="Wrap"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<Button Name="Btn_Answer" Content="Ansewr" HorizontalAlignment="Left" Grid.Row="1" VerticalAlignment="Bottom" Click="Btn_Answer_Click"/>
My application is a quiz application that offer 4 choices/options as answers for each question, and when user select a true answer, I want to highlight the true answer(true choice) by make its background to green, and if the user selected wrong answer/option I want to make the background of that answer (a specific List View item) with red.
Any help please ?
You're not going to be able to access an element inside a data template like that. Instead, leverage the binding to a view model to set the color and other view-related properties. First, create a wrapper view model for your data class:
public class MyTBLViewModel : INotifyPropertyChanged
{
public MyTBL Entity
{
get { return _entity; }
}
private readonly MyTBL _entity;
public Brush Highlight
{
get { return _brush; }
set
{
_brush = value;
RaisePropertyChanged("Highlight");
}
}
private Brush _highlight;
public double ItemFontSize
{
get { return _itemFontSize; }
set
{
_itemFontSize = value;
RaisePropertyChanged("ItemFontSize");
}
}
private Brush _itemFontSize;
public MyTBLViewModel(MyTBL entity)
{
_entity = entity;
_highlight = new SolidColorBrush(Colors.Transparent);
_itemFontSize = 12;
}
public event PropertyChangedEventArgs PropertyChanged;
protected void RaisePropertyChanged(string propName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propName));
}
}
Use this as your ItemsSource:
List<MyTBLViewModel> t_list = db1.GetTable("SELECT * FROM MyTBL LIMIT 4 ORDER BY RANDOM() ;")
.AsEnumerable().Select(entity => new MyTBLViewModel(entity)).ToList();
Now in your view, bind the view elements to "Highlight" and "ItemFontSize", and to any other properties you like:
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="6" Background="{Binding Highlight}">
<StackPanel VerticalAlignment="Top" Margin="10,0,0,0">
<TextBlock Name="TB_AMean1" Text="{Binding Entity.AMean1}" TextWrapping="Wrap"
FontSize="{Binding ItemFontSize}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
Finally, you can get the data item from the SelectionChangedEventArgs -- use it to update your view-related properties:
private void LV_Options_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var item in e.AddedItems.OfType<MyTBLViewModel>())
{
item.Highlight = new SolidColorBrush(Color.LightSteelBlue);
item.ItemFontSize = 17;
}
foreach (var item in e.RemovedItems.OfType<MyTBLViewModel>())
{
item.Highlight = new SolidColorBrush(Colors.Transparent);
item.ItemFontSize = 12;
}
}
var item = LV_Options.Items.ElementAt(3);
This line is incorrect. It will not return you a TextBlock. I don't know what a .BackColor is, and it should not compile. The Items property in a ListView will return you a list of ListViewItems. If you want to access the inside element from a ListViewItem, you'll need to access the ContentTemplateRoot property.
Do not use var ever. It lets you assume that you know the type, whereas if you explicitly typed the declaration you would realize you're doing it wrong.
MyTBL wrd = lv1.SelectedItem as MyTBL;
if (wrd == null)
return;
TextBlock tb = lv1.FindName("TB_AMean1") as TextBlock;
What is a MyTBL type? FindName is only available to framework DependencyObjects so I'm assuming it's a user control? You have to provide a lot more code to show us what you're doing and what you're setting the ListView's ItemsSource and ItemTemplate with and what these errors are and how you have 2 breaking debug errors at once and what the error messages are.
Comprehending runtime error messages is a huge part of being a good developer.