I found function to print content of Wpf grid but the print is cropped.
Can anybody know why?
the function:
private void PrintTest()
{
FlowDocument document;
Window window;
CreateWindowToPrint(out document, out window);
PrintDialog printDialog = new PrintDialog();
window.Show();
IDocumentPaginatorSource dps = document;
if (printDialog.ShowDialog() == true)
{
printDialog.PrintDocument(dps.DocumentPaginator, "test");
}
}
and:
private void CreateWindowToPrint(out FlowDocument document, out
Window window)
{
document = new FlowDocument { };
var test = new PrintedTest() { DataContext = this.DataContext };
document.Blocks.Add(new BlockUIContainer { Child = test });
window = new Window {Content = document, Visibility = System.Windows.Visibility.Hidden };
}
The UserControl PrintedTest contains my grid.
I don't really have much experience with printing in WPF but I thought I would give it a try.
I could reproduce your problem, and I could not solve it so far.
But In my research I have found an alternative, which is more simple to print the Grid:
var printDialog = new PrintDialog();
var result = printDialog.ShowDialog();
if (result.HasValue && result.Value)
{
var testControl = new PrintedTest() { DataContext = this.DataContext };
printDialog.PrintVisual(testControl, "My WPF printing a DataGrid");
}
Instead of sending the PrintTest you could actually just send directly the grid.
Related
The following code is supposed to scroll an item into view and set focus to the first child control in the template:
lv.ScrollIntoView(lv.SelectedItem);
var lvi = lv.SelectedListViewItem();
//get the item's template parent
var templateParent = lvi.GetFrameworkElementByName<ContentPresenter>();
if (templateParent != null) <--but it's always null
{
var ctrl = templateParent.FindVisualChildren<FrameworkElement>().First();
ctrl.Focus();
}
The problem is that if the ListViewItem is not visible, then templateParent is null, and this code doesn't work. And of course this code is only useful when the item isn't already visible.
Is there a way to scroll the item into view and then be notified when it has come into view so that the template will be non-null so that the ctrl.Focus() code would execute?
You could handle the RequestBringIntoView event. Please refer to the following sample code.
public MainWindow()
{
InitializeComponent();
lv.ItemsSource = Enumerable.Range(1, 100);
lv.SelectedItem = 90;
lv.ScrollIntoView(lv.SelectedItem);
lv.RequestBringIntoView += Lv_RequestBringIntoView;
}
private void Lv_RequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
{
var container = lv.ItemContainerGenerator.ContainerFromItem(lv.SelectedItem);
if (container != null)
{
//...
}
}
I have winforms application that contains cefsharp ChromiumWebBrowser component. I want JAWS to read it's content. Now JAWS only read title of main window. Is there any way to achieve this? I tried "force-renderer-accessibility" flag but it didn't help me.
Here is the code i tried:
var settings = new CefSettings()
{
CefCommandLineArgs = { new KeyValuePair<string, string>("force-renderer-accessibility", "true") }
};
Cef.Initialize(settings, performDependencyCheck: false, browserProcessHandler: null);
Following amaitland's prompting above we found the following solution.
Disable MultiThreadedMessageLoop - you then need to periodically invoke DoMessageLoopWork as per the crude sample below.
var settings = new CefSettings()
{
MultiThreadedMessageLoop = false
};
Cef.Initialize(settings);
browser = new ChromiumWebBrowser ("https://url.com/");
var t = new Timer {Interval = 5};
t.Start();
t.Tick += t_Tick;
this.panel1.Controls.Add(browser);
}
void t_Tick(object sender, EventArgs e)
{
this.BeginInvoke((Action) (() => Cef.DoMessageLoopWork()));
}
I'm trying change the line thickness in a serie dinamically created, I need turn the line more thick.
Below, follow the code to bind the created serie on chart component. It works fine, but I tryed adapt this in this code and I had no sucess.
Please help, thanks.
Style style = new Style(typeof(LineDataPoint));
style.Setters.Add(new Setter(LineDataPoint.OpacityProperty, (double)(0.0)));
style.Setters.Add(new Setter(LineDataPoint.BackgroundProperty, dadosSerie.ColorSerie));
LineSeries lineSerie = new LineSeries()
{
Title = dadosSerie.SerieTitle,
IndependentValueBinding = new Binding("Key"),
DependentValueBinding = new Binding("Value"),
DependentRangeAxis = dadosSerie.EixoY,
DataPointStyle = style,
ItemsSource = dadosSerie.DataSerie,
};
chtGraficos.Series.Add(lineSerie);
Have you tried adding a Style for the serie's Polyline instead?
It seams the style for the LineDataPoint is actually for every point on the serie.
Here is a working sample of a chart fully created on code-behind. You just have to create a window named MainWindow and add a reference on the project to System.Windows.Controls.DataVisualization.Toolkit:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var valueList = new Dictionary<string, int>();
valueList.Add("Developer", 60);
valueList.Add("Misc", 20);
valueList.Add("Project Manager", 40);
var style = new Style(typeof(Polyline));
style.Setters.Add(new Setter(Polyline.StrokeThicknessProperty, 10d));
var series = new LineSeries
{
PolylineStyle = style,
ItemsSource = valueList,
DependentValuePath = "Value",
IndependentValuePath = "Key",
};
var lineChart = new Chart { Height = 254 };
lineChart.Series.Add(series);
var mainGrid = new Grid();
mainGrid.Children.Add(lineChart);
this.Content = mainGrid;
}
}
I have a control that placed into a custom panel. Into view model exist a boolean variable IsStandAlone. I wish when IsStandAlone is true that this control will be in new window.
I do this on setting IsStandAlone to true:
var window = new Window();
window.Content = this;
window.Closed += (s, ea) =>
{
window.Content = null;
ViewModel.IsStandAlone = false;
}
window.Show();
It's work good when i set IsStandAlone true but when i close the window control doesn't appear in the panel.
Like this?
...
If(IsStandAlone){
var newWindow = new MyNewWindow();
newWindow.Show();
}
...
TextBox has a default context menu. I would like to add an item to it. OK, that means cloning the default one, and adding an extra item to that.
I'd like to reuse some code here. I have five textboxes. Each needs the additional item on its context menu. The item needs act on the textbox that was clicked. I know "copy and paste" is the recommended method of code reuse in WPF, but if possible I'd prefer not to define five menus in XAML and five commands in the code behind.
Is there any reasonably clean and quick way to do this in WPF?
public partial class MyGhastlyView
{
/* blah blah */
private void MenuCut_Click(object sender, RoutedEventArgs e)
{
try
{
(sender as MenuItem).GetPlacementTarget<TextBox>().Cut();
}
catch (Exception)
{
}
}
/* blah blah */
}
public static class FurshlugginerExtensions
{
public static bool TryGetPlacementTarget<TTargetType>(this MenuItem mi,
out TTargetType target) where TTargetType : class
{
target = null;
var cm = mi.GetContextMenu();
if (null != cm)
{
target = cm.PlacementTarget as TTargetType;
}
return null != target;
}
public static TTargetType GetPlacementTarget<TTargetType>(this MenuItem mi)
where TTargetType : class
{
var cm = mi.GetContextMenu();
return (cm == null)
? null
: cm.PlacementTarget as TTargetType;
}
public static ContextMenu GetContextMenu(this MenuItem mi)
{
var logicalParent = LogicalTreeHelper.GetParent(mi);
if (logicalParent is ContextMenu)
{
return logicalParent as ContextMenu;
}
else if (logicalParent is MenuItem)
{
return (logicalParent as MenuItem).GetContextMenu();
}
return null;
}
}
UPDATE
What I'm looking for turns out to be a RoutedUICommand, with some futzing around in XAML. It knows what you clicked on (with some Kafkaesque exceptions due to event bubbling -- but can just set the CommandParameter on the ContextMenu).
Unfortunately, ContextMenuOpening event will not work here. For whatever reason, TextBox does not expose its context menu, and is always null unless you set it with your own. Perhaps it simply pops a private menu on right mouse click.
Charles Petzold speaks about that with RichTextBox here. (Both TextBox and RichTextBox derive from TextBoxBase, which appears to define that behavior)
It seems you will have to create your own, and duplicate the existing items.
Several articles demonstrate exactly this, like the one here.
Hope this helps.
EDIT:
However if you insist on editing the current menu, it appears someone has done so here (using an extension method and reflection).
After further investigation of the above attempt, it seems that the author is creating an instance of an EditorContextMenu (private class which derives from ContextMenu in System.Windows.Documents) and assigning it to the TextBox ContextMenu property, then adding the parameter menu items to the newly created menu. In effect, overriding the current menu. While you do get the original implementation, I am not sure I would favor this solution.
EDIT 2:
The following code will create only one instance of custom menu, bind Ctrl-D to the textboxes, along with the correlating ContextMenu item.
public static RoutedCommand ItemActionCommand = new RoutedCommand();
public MainWindow()
{
InitializeComponent();
CommandBinding commandBinding = new CommandBinding(ItemActionCommand, new ExecutedRoutedEventHandler(ItemActionCommandEventHandler));
KeyBinding keyBinding = new KeyBinding(ItemActionCommand, new KeyGesture(Key.D, ModifierKeys.Control));
MenuItem item = new MenuItem();
item.Click += CustomContextMenuItem_Click; // not really necessary
item.Header = "Custom Menu Item";
item.InputGestureText = "Ctrl+D";
item.Command = ItemActionCommand;
ContextMenu menu = new ContextMenu();
menu.Items.Add(item);
Grid container = new Grid();
this.Content = container;
for (int i = 0; i < 5; i++)
container.Children.Add(this.CreateTextBox("Value: " + i.ToString(), (i + 1) * 30.0d, menu, commandBinding, keyBinding));
}
private void ItemActionCommandEventHandler(object sender, ExecutedRoutedEventArgs e)
{
TextBox textBox = e.Source as TextBox;
Debug.Assert(textBox != null);
// perform actions against textbox here
}
private void CustomContextMenuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem item = sender as MenuItem;
Debug.Assert(item != null);
TextBox textBox = ((ContextMenu)item.Parent).PlacementTarget as TextBox;
Debug.Assert(textBox != null);
// no need to do anything here since the command handler above will fire
// but for the sake of completeness
}
private TextBox CreateTextBox(string text, double topOffset, ContextMenu menu, CommandBinding commandBinding, KeyBinding keyBinding)
{
TextBox textbox = new TextBox();
textbox.HorizontalAlignment = HorizontalAlignment.Center;
textbox.VerticalAlignment = VerticalAlignment.Top;
textbox.Margin = new Thickness(0.0d, topOffset, 0.0d, 0.0d);
textbox.CommandBindings.Add(commandBinding);
textbox.InputBindings.Add(keyBinding);
textbox.ContextMenu = menu;
textbox.Width = 150.0d;
textbox.Height = 25.0d;
textbox.Text = text;
return textbox;
}
Screenshot:
It is possible with an AttachedProperty and the handling of the ContextMenuOpening event. Look here and here. Should take around 100 lines of code and one line in xaml.
For completenes sake:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfApplication1
{
public class CustomMenuAction
{
public static bool GetHasMenuItemAction(DependencyObject obj)
{
return (bool)obj.GetValue(HasMenuItemActionProperty);
}
public static void SetHasMenuItemAction(DependencyObject obj, bool value)
{
obj.SetValue(HasMenuItemActionProperty, value);
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HasMenuItemActionProperty =
DependencyProperty.RegisterAttached("HasMenuItemAction", typeof(bool), typeof(CustomMenuAction), new PropertyMetadata(default(bool),OnPropertyChanged));
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if((bool)e.NewValue)
{
var textbox = d as TextBox;
if(textbox != null)
{
textbox.ContextMenu = GetCustomContextMenu();
textbox.ContextMenuOpening += textbox_ContextMenuOpening;
}
}
}
private static ContextMenu GetCustomContextMenu()
{
var contextMenu = new ContextMenu();
var standardCommands = GetStandardCommands();
foreach (var item in standardCommands)
{
contextMenu.Items.Add(item);
}
return contextMenu;
}
private static IList<MenuItem> GetStandardCommands()
{
//From https://stackoverflow.com/a/210981/3411327
List<MenuItem> standardCommands = new List<MenuItem>();
MenuItem item = new MenuItem();
item.Command = ApplicationCommands.Cut;
standardCommands.Add(item);
item = new MenuItem();
item.Command = ApplicationCommands.Copy;
standardCommands.Add(item);
item = new MenuItem();
item.Command = ApplicationCommands.Paste;
standardCommands.Add(item);
return standardCommands;
}
static void textbox_ContextMenuOpening(object sender, ContextMenuEventArgs e)
{
//From MSDN example: http://msdn.microsoft.com/en-us/library/bb613568.aspx
var textbox = e.Source as TextBox;
ContextMenu cm = textbox.ContextMenu;
foreach (MenuItem mi in cm.Items)
{
if ((String)mi.Header == "Item4") return;
}
MenuItem mi4 = new MenuItem();
mi4.Header = "Item4";
mi4.Click += (o, args) =>
{
var menuItem = o as MenuItem;
MessageBox.Show(menuItem.Header.ToString(), textbox.Text);
};
textbox.ContextMenu.Items.Add(mi4);
}
}
}
<TextBox namespace:CustomMenuAction.HasMenuItemAction="True"></TextBox>