Only one selected item allowed in ListView - compact-framework

I need only one ListView item selectable. I can not find poperty/method to disable multiple selection in .NET Compact Framework 3.5. And I can not find ListView2 in OpenNetCF.

You could use a ListBox Control. It can be made to look and function like the ListView Control.
If you want (or need) to stick with the ListView Control, you could always select the first item in the SelectionIndexChanged event and discard the rest.
void ListView1_SelectedIndexChanged(object sender, System.EventArgs e) {
for (int i = 0; i < ListView1.SelectedItems.Count; i++) {
ListViewItem item = ListView1.SelectedItems[i];
if (i == 0) {
Console.WriteLine(item.ToString());
} else {
item.Selected = false;
}
}
}

Related

Remove border of a tabcontrolbox in visual studio 2015 [duplicate]

How can I make a transparent tabPage? I found solutions like set both Form's BackColor and TransparencyKey to a color like Color.LimeGreen or override OnPaintBackground with a empty method but TabPage doesn't have neither TransparencyKeyproperty norOnPaintBackground` method. How can I do that?
TabControl is a native Windows component, it always draws the tab pages opaque with no built-in support for transparency. Solving this requires a little helping of out-of-the-box thinking, a tab control with transparent tab pages simply devolves to just the tabstrip being visible. All you have to do is use panels to host the controls that are now on the tab pages and make the correct one visible with the SelectedIndexChanged event.
Best to stick this in a derived class so you can still use the tab control normally at design time. Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto the form, replacing the existing one.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
class TransparentTabControl : TabControl {
private List<Panel> pages = new List<Panel>();
public void MakeTransparent() {
if (TabCount == 0) throw new InvalidOperationException();
var height = GetTabRect(0).Bottom;
// Move controls to panels
for (int tab = 0; tab < TabCount; ++tab) {
var page = new Panel {
Left = this.Left, Top = this.Top + height,
Width = this.Width, Height = this.Height - height,
BackColor = Color.Transparent,
Visible = tab == this.SelectedIndex
};
for (int ix = TabPages[tab].Controls.Count - 1; ix >= 0; --ix) {
TabPages[tab].Controls[ix].Parent = page;
}
pages.Add(page);
this.Parent.Controls.Add(page);
}
this.Height = height /* + 1 */;
}
protected override void OnSelectedIndexChanged(EventArgs e) {
base.OnSelectedIndexChanged(e);
for (int tab = 0; tab < pages.Count; ++tab) {
pages[tab].Visible = tab == SelectedIndex;
}
}
protected override void Dispose(bool disposing) {
if (disposing) foreach (var page in pages) page.Dispose();
base.Dispose(disposing);
}
}
Call the MakeTransparent() method in the form's Load event handler:
private void Form1_Load(object sender, EventArgs e) {
transparentTabControl1.MakeTransparent();
}

MasterDetailView UWP - Access the ListView (or make it scroll)

I recently discovered the UWP Community Toolkit and I loved it. I'm using now the MasterDetailView and it's almost perfect for what I need: but it's missing one important thing: I cannot access the internal "ListView".
In my application I have two buttons: forward and back, and when pressing them I simply go forward and back in the list. I found a trick to access the prev/next element doing like this:
public void GoForward()
{
if (MasterDetailView.Items.Count > 0)
{
bool isNextGood = false;
MyItem selectedItem = MasterDetailView.Items[MasterDetailView.Items.Count - 1] as MyItem;
foreach (var v in MasterDetailView.Items)
{
if (isNextGood)
{
selectedItem = v as MyItem;
break;
}
if (v == MasterDetailView.SelectedItem)
isNextGood = true;
}
MasterDetailView.SelectedItem = selectedItem;
}
}
This just because I cannot access the "SelectedIndex" and I have only SelectedItem avaiable. Now, obviously not all the item can be visible at the same time, so MasterDetailView provide a lateral ListView with a scrollbar. When pressing my next/prev buttons SelectedItem changes, but doesn't scroll at the selected element: selection goes forward/back but the list is locked. This produce a very negative feedback because I lost my selection somewhere in the list and I must search it.
How I though to solve it? I try this approaches:
1) Find the style for MasterDetailView. Inside I found a ListViewStyle, so I tried to put inside a simple "SelectionChanged" event and handle it at App.xaml.cs.
<ListView x:Name="MasterList"
Grid.Row="1"
IsTabStop="False"
ItemContainerStyle="{TemplateBinding ItemContainerStyle}"
ItemTemplate="{TemplateBinding ItemTemplate}"
ItemTemplateSelector="{TemplateBinding ItemTemplateSelector}"
ItemsSource="{TemplateBinding ItemsSource}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
SelectionChanged="MasterList_SelectionChanged"/>
CS:
private void MasterList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListView list = sender as ListView;
list.ScrollIntoView(list.SelectedItem);
}
But, as said, "Events cannot be set in the Application class XAML file".
2) Think about taking the parent of SelectedItem: I tried to convert the SelectedItem in ListViewItem, then access the parent, but it fails at first conversion, as the SelectedItem seems no to be a ListViewItem, but it's of the "MyItem" type. Like this, I cannot access the parent.
private void MasterDetailView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var item = MasterDetailView.SelectedItem as ListViewItem;
var parent = item.Parent;
var list = parent as ListView;
}
And so I'm here... I don't want to throw away all my work with the MasterDetailView to pass to another control. Is there any simple method to access the list, or simply, scroll the list when I'm changing selection? Just wanna to do one thing, like this:
private void List_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListView list = sender as ListView;
list.ScrollIntoView(list.SelectedItem);
}
Simply scrolling into selection when selection changed occurred, but I have no simple ListView but a MasterDetailView control. Even if it's done entirely in XAML: the most important thing for me is make scroll this list!
Thanks.
 
 
Solution
This method is fantastic. Just copy-paste.
public static T FindChildOfType<T>(DependencyObject root) where T : class
{
var queue = new Queue<DependencyObject>();
queue.Enqueue(root);
while (queue.Count > 0)
{
DependencyObject current = queue.Dequeue();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(current); i++)
{
var child = VisualTreeHelper.GetChild(current, i);
var typedChild = child as T;
if (typedChild != null)
{
return typedChild;
}
queue.Enqueue(child);
}
}
return null;
}
Then simply use it to retrive the list and make it scroll. Yes babe!
private void MasterDetailView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var v = FindChildOfType<ListView>(MasterDetailView);
v.ScrollIntoView(MasterDetailView.SelectedItem);
}
Please note that "MasterDerailView" Is the x:Name of my element, not the class.
You can use a FindChildOfType implementation to get the ListView through VisualTreeHelper, as indicated in this answer:
Windows UWP - How to programmatically scroll ListView in ContentTemplate

ListView flickering when updating binding collection

I am working on a Windows 10 Universal app and see some flickering issues when I use a ListView in my app. My ListView is using x:Bind to bind to an ObservableCollection in my View Model.
When user performs some actions, or a background update occurs, I do some processing that requires the ObservableCollection to be refreshed.
private ObservableCollection<Item> UIItems = new ObservableCollection<Item>();
private bool IsUpdating = false;
private void UpdateUIProperties(List<Item> newItems)
{
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
IsUpdating = true;
UIItems.Clear();
foreach (var item in newItems)
{
if (item.IsVisible)
{
UIItems.Add(item);
}
}
IsUpdating = false;
});
}
After this code gets executed, the ListView flickers and then the Scrollviewer goes all the way to the top. Is there any way to prevent this and have the ListView's ScrollViewer stay at its original offset?
A solution that seem to work for me is to bind the Itemsource to an Observable collection and then have another collection that contains the items that you want to add. Have the Item in the collection implement the interface below. When you want to update the collection use the MergeCollection method to make sure the items in the collection are preserved, but they have the new config.
public interface IConfigureFrom<T>
{
void ConfigureFrom(T other);
}
public static void MergeCollection<T>(ICollection<T> source, ICollection<T> dest) where T : IConfigureFrom<T>, new()
{
// First remove entries at the bottom of the dest list that are no longer there
if (dest.Count > source.Count)
{
for (int i = dest.Count - 1; i >= source.Count; i--)
{
var coll = dest as Collection<T>;
if (coll != null)
{
coll.RemoveAt(i);
}
else
{
dest.Remove(dest.Last());
}
}
}
// reconfigure existing entries with the new configureation
var sourecList = source.ToList();
var destList = dest.ToList();
for (int i = dest.Count - 1; i >= 0; i--)
{
var target = destList[i];
var config = sourecList[i];
target.ConfigureFrom(config);
}
// add new entries at the end and configure them from the source list
for (int i = dest.Count; i < source.Count; i++)
{
T newItem = new T();
newItem.ConfigureFrom(sourecList[i]);
dest.Add(newItem);
}
}
When changing all items in your ListView, it is usually better to just swap the whole ItemsSource.
Just set:
UIItems = new List<...>(your data);
And have it fire OnNotifyPropertyChanged of course.

XAML: Tap a textbox to enable?

In XAML and WinRT, Is there a way to set up a textbox so that it is disabled for text input until it is tapped.
I tried setting up the Tapped event and then setting the IsEnabled=true, but that only seems to work if the IsEnabled=true in the first place.
I found this on MSDN:
http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/708c0949-8b06-40ec-85fd-201139ca8b2d
Talks about adding the TappedEvent manually to the event handled for each TextBox, which is cumbersome, but also doesn't seem to work unless IsEnabled was already set to true.
Basically, I want a form where all textboxes display data but are disabled unless the user taps to enable the box and then type.
You can use IsReadOnly instead of IsEnabled to achieve what you are looking for. In addition, you can set up the tapped event handlers in code easily. I'm not sure if setting up handlers in code is a requirement for this to work, as you noted above; however, it does simplify things.
Here are the details.
In the constructor of your page class (here it is MainPage), call the setup function:
public MainPage()
{
this.InitializeComponent();
// call the setup for the textboxes
SetupTextBoxes();
}
Here is where we do the magic - make all textboxes on this page readonly and set up tap handler:
private void SetupTextBoxes()
{
var tbs = GetVisualChildren<TextBox>(this, true);
foreach (var tb in tbs)
{
tb.IsReadOnly = true;
tb.AddHandler(TappedEvent, new TappedEventHandler(tb_Tapped), true);
}
}
Utility function to get a list of all children of the given type (T) of the passed in parent.
private List<T> GetVisualChildren<T>(DependencyObject parent, bool recurse = true)
where T : DependencyObject
{
var children = new List<T>();
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
DependencyObject v = (DependencyObject)VisualTreeHelper.GetChild(parent, i);
var child = v as T;
if (child == null && recurse)
{
var myChildren = GetVisualChildren<T>(v, recurse);
children.AddRange(myChildren);
}
if (child != null)
children.Add(child);
}
return children;
}
Finally, the event handler. This enables each textbox when tapped.
private void tb_Tapped(object sender, TappedRoutedEventArgs e)
{
((TextBox)(sender)).IsReadOnly = false;
}

ReportViewer - modify toolbar?

Do anyone have good ideas of how to modify the toolbar for the WinForms version of the ReportViewer Toolbar?
That is, I want to remove some buttons and varius, but it looks like the solution is to create a brand new toolbar instead of modifying the one that is there.
Like, I had to remove export to excel, and did it this way:
// Disable excel export
foreach (RenderingExtension extension in lr.ListRenderingExtensions()) {
if (extension.Name == "Excel") {
//extension.Visible = false; // Property is readonly...
FieldInfo fi = extension.GetType().GetField("m_isVisible", BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(extension, false);
}
}
A bit trickysh if you ask me..
For removing toolbarbuttons, an possible way was to iterate through the Control array inside the ReportViewer and change the Visible property for the buttons to hide, but it gets reset all the time, so it is not an good way..
WHEN do MS come with an new version btw?
Yeap. You can do that in a little tricky way.
I had a task to add more scale factors to zoom report. I did it this way:
private readonly string[] ZOOM_VALUES = { "25%", "50%", "75%", "100%", "110%", "120%", "125%", "130%", "140%", "150%", "175%", "200%", "300%", "400%", "500%" };
private readonly int DEFAULT_ZOOM = 3;
//--
public ucReportViewer()
{
InitializeComponent();
this.reportViewer1.ProcessingMode = ProcessingMode.Local;
setScaleFactor(ZOOM_VALUES[DEFAULT_ZOOM]);
Control[] tb = reportViewer1.Controls.Find("ReportToolBar", true);
ToolStrip ts;
if (tb != null && tb.Length > 0 && tb[0].Controls.Count > 0 && (ts = tb[0].Controls[0] as ToolStrip) != null)
{
//here we go if our trick works (tested at .NET Framework 2.0.50727 SP1)
ToolStripComboBox tscb = new ToolStripComboBox();
tscb.DropDownStyle = ComboBoxStyle.DropDownList;
tscb.Items.AddRange(ZOOM_VALUES);
tscb.SelectedIndex = 3; //100%
tscb.SelectedIndexChanged += new EventHandler(toolStripZoomPercent_Click);
ts.Items.Add(tscb);
}
else
{
//if there is some problems - just use context menu
ContextMenuStrip cmZoomMenu = new ContextMenuStrip();
for (int i = 0; i < ZOOM_VALUES.Length; i++)
{
ToolStripMenuItem tsmi = new ToolStripMenuItem(ZOOM_VALUES[i]);
tsmi.Checked = (i == DEFAULT_ZOOM);
//tsmi.Tag = (IntPtr)cmZoomMenu;
tsmi.Click += new EventHandler(toolStripZoomPercent_Click);
cmZoomMenu.Items.Add(tsmi);
}
reportViewer1.ContextMenuStrip = cmZoomMenu;
}
}
private bool setScaleFactor(string value)
{
try
{
int percent = Convert.ToInt32(value.TrimEnd('%'));
reportViewer1.ZoomMode = ZoomMode.Percent;
reportViewer1.ZoomPercent = percent;
return true;
}
catch
{
return false;
}
}
private void toolStripZoomPercent_Click(object sender, EventArgs e)
{
ToolStripMenuItem tsmi = sender as ToolStripMenuItem;
ToolStripComboBox tscb = sender as ToolStripComboBox;
if (tscb != null && tscb.SelectedIndex > -1)
{
setScaleFactor(tscb.Items[tscb.SelectedIndex].ToString());
}
else if (tsmi != null)
{
if (setScaleFactor(tsmi.Text))
{
foreach (ToolStripItem tsi in tsmi.Owner.Items)
{
ToolStripMenuItem item = tsi as ToolStripMenuItem;
if (item != null && item.Checked)
{
item.Checked = false;
}
}
tsmi.Checked = true;
}
else
{
tsmi.Checked = false;
}
}
}
Get the toolbar from ReportViewer control:
ToolStrip toolStrip = (ToolStrip)reportViewer.Controls.Find("toolStrip1", true)[0]
Add new items:
toolStrip.Items.Add(...)
There are a lot of properties to set which buttons would you like to see.
For example ShowBackButton, ShowExportButton, ShowFindControls, and so on. Check them in the help, all starts with "Show".
But you are right, you cannot add new buttons. You have to create your own toolbar in order to do this.
What do you mean about new version? There is already a 2008 SP1 version of it.
Another way would be to manipulate the generated HTML at runtime via javascript. It's not very elegant, but it does give you full control over the generated HTML.
For VS2013 web ReportViewer V11 (indicated as rv), the code below adds a button.
private void AddPrintBtn()
{
foreach (Control c in rv.Controls)
{
foreach (Control c1 in c.Controls)
{
foreach (Control c2 in c1.Controls)
{
foreach (Control c3 in c2.Controls)
{
if (c3.ToString() == "Microsoft.Reporting.WebForms.ToolbarControl")
{
foreach (Control c4 in c3.Controls)
{
if (c4.ToString() == "Microsoft.Reporting.WebForms.PageNavigationGroup")
{
var btn = new Button();
btn.Text = "Criteria";
btn.ID = "btnFlip";
btn.OnClientClick = "$('#pnl').toggle();";
c4.Controls.Add(btn);
return;
}
}
}
}
}
}
}
}
I had this question for al ong time I I found the answer after a long tie and the main source of kowledge I used was this webpega: I'd like to thank you all guys adding the code that allowed me to do it and a picture with the result.
Instead of using the ReportViewer Class, you need to create a new classs, in my case, I named it ReportViewerPlus and it goes like this:
using Microsoft.Reporting.WinForms;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace X
{
class ReportViewerPlus : ReportViewer
{
private Button boton { get; set; }
public ReportViewerPlus(Button but) {
this.boton = but;
testc(this.Controls[0]);
}
public ReportViewerPlus()
{
}
private void testc(Control item){
if(item is ToolStrip)
{
ToolStripItemCollection tsic = ((ToolStrip)item).Items;
tsic.Insert(0, new ToolStripControlHost(boton));
return;
}
for (int i = 0; i < item.Controls.Count; i++)
{
testc(item.Controls[i]);
}
}
}
}
You have to add the button directly in the constructor of the class and you can configure the button in your designer.
Here's a pic of the result, not perfect, but enough to go(safe link I swear, but I can't post my own pics, don't have enough reputation).
http://prntscr.com/5lfssj
If you look carefully in the code of the class, you'd see more or less how it works and you could make your changes and make it possible to establish it in other site of the toolbar.
Thank you so much for helping me in the past, I hope this helps lots of people!
Generally you are suppose to create your own toolbar if you want to modify it. Your solution for removing buttons will probably work if that is all you need to do, but if you want to add your own you should probably just bite the bullet and build a replacement.
You may modify reportviewer controls by CustomizeReportToolStrip method.
this example remove Page Setup Button, Page Layout Button in WinForm
public CustOrderReportForm() {
InitializeComponent();
CustomizeReport(this.reportViewer1);
}
private void CustomizeReport(Control reportControl, int recurCount = 0) {
Console.WriteLine("".PadLeft(recurCount + 1, '.') + reportControl.GetType() + ":" + reportControl.Name);
if (reportControl is Button) {
CustomizeReportButton((Button)reportControl, recurCount);
}
else if (reportControl is ToolStrip) {
CustomizeReportToolStrip((ToolStrip)reportControl, recurCount);
}
foreach (Control childControl in reportControl.Controls) {
CustomizeReport(childControl, recurCount + 1);
}
}
//-------------------------------------------------------------
void CustomizeReportToolStrip(ToolStrip c, int recurCount) {
List<ToolStripItem> customized = new List<ToolStripItem>();
foreach (ToolStripItem i in c.Items) {
if (CustomizeReportToolStripItem(i, recurCount + 1)) {
customized.Add(i);
}
}
foreach (var i in customized) c.Items.Remove(i);
}
//-------------------------------------------------------------
void CustomizeReportButton(Button button, int recurCount) {
}
//-------------------------------------------------------------
bool CustomizeReportToolStripItem(ToolStripItem i, int recurCount) {
Console.WriteLine("".PadLeft(recurCount + 1, '.') + i.GetType() + ":" + i.Name);
if (i.Name == "pageSetup") {
return true;
}
else if (i.Name == "printPreview") {
return true;
}
return false; ;
}