2019年1月31日 星期四

[學習] reportviewer hide export pdf excel word 禁止RDLC輸出某格式

〔winform〕 

VB.NET
Private Sub ReportViewer1_RenderingBegin(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles ReportViewer1.RenderingBegin
    Dim info As FieldInfo
    For Each extension In Me.ReportViewer1.LocalReport.ListRenderingExtensions()
        If extension.Name = "PDF" Then
            info = extension.GetType().GetField("m_isVisible", BindingFlags.Instance Or BindingFlags.NonPublic)
            info.SetValue(extension, False)
        End If
    Next
End Sub

C#
//string exportOption = "Excel";
//string exportOption = "Word";
string exportOption = "PDF";
RenderingExtension extension = reportViewer1.LocalReport.ListRenderingExtensions().ToList().Find(x => x.Name.Equals(exportOption, StringComparison.CurrentCultureIgnoreCase));
if (extension != null)
{
                System.Reflection.FieldInfo fieldInfo = extension.GetType().GetField("m_isVisible", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
                fieldInfo.SetValue(extension, false);
}

參考:
禁止ReportViewer工具栏上的导出按钮?
reportviewer禁止导出Excel按钮
ReportViewer - Hide PDF Export
ReportViewer 2010:how to hide pdf in export option in reportviewer
Hide (Disable) specific export option in ReportViewer from Export button
Hide (Disable) specific export option (Word / Excel / PDF) from Export button

2019年1月15日 星期二

[除錯] 轉換至可為Null的型別, Convert to Nullable

轉換DataTable至List<T>時,當自訂義的物件<T>包含Nullable的型別,則會引發錯誤

原本型別轉換
pro.SetValue(objT, (row[pro.Name] == DBNull.Value ? null : Convert.ChangeType(row[pro.Name], pI.PropertyType)), null);

改成
pro.SetValue(objT, (row[pro.Name] == DBNull.Value ? null : ChangeType(row[pro.Name], pI.PropertyType)), null);


        //轉換為可為 Null 的型別
        public static object ChangeType(object value, Type conversion)
        {
            var t = conversion;

            if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
            {
                if (value == null)
                {
                    return null;
                }

                t = Nullable.GetUnderlyingType(t);
            }

            return Convert.ChangeType(value, t);
        }


錯誤訊息:
Invalid cast from 'System.Int32' to 'System.Nullable`

從 'System.Decimal' 至 'System.Nullable`1[[System.Decimal, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' 的轉換無效。

參考:
Invalid cast from 'System.Int32' to 'System.Nullable`1[[System.Int32, mscorlib]]
C#将数据转换为指定类型,支持对可空类型(Nullable类)转换方法示例

我们知道在C#中,引用类型可以为null,而值类型不可以为null,就是值类型必须要有值。msdn上面的解释是值类型没有足够的空量来表示空值,它的容量只够表示适合该类型的值,没有多余的容量。而数据库中(比如sqlserver)中,任何类型的值都是可以为null的,这就给我们在往数据库中插入值带来麻烦了,比如要往数据库中的int字段中插入一个null值,而C#在2.0之前,是不可能给一个int类型的变量赋于null的。

为了解决这个问题,C#引入了Nullable类,该类为值类型赋于null值提供了支持,如果我们要为一个int类型赋于null值,那么我们就可以声明该类型为Nullable<int >,也可以直接缩写为int?,这就是我们在C#2.0后版本中看到的大量可为空的值类型声明方式。

基础基元类型的概念:
可空类型的原类型称之为该类型的基础基元类型,比如我们声明了变量int?,那么我们就称int为int?的基础基元类型。

明白了这些概念后,现在假设我们要写一个方法,该方法要支持将一个object类型的值转换为任何可能转换的类型。
该类有两个参数,值value,类型convertsionType,
如果不支持可空类型,那么该方法很好实现,如下:
public static object ChanageType(object value, Type convertsionType)
{
return Convert.ChangeType(value, convertsionType);
}


但如果convertsionType为可空类型,该方法就会报类似如下错误了:
从“System.String”到“System.Nullable`1[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]”的强制转换无效。

所以改写方法如下:
public static class PageBaseHelper
{
    public static object SD_ChanageType(this object value, Type convertsionType)
    {
        //判断convertsionType类型是否为泛型,因为nullable是泛型类,
        if (convertsionType.IsGenericType &&
            //判断convertsionType是否为nullable泛型类
            convertsionType.GetGenericTypeDefinition().Equals(typeof(Nullable< >)))
        {
            if (value == null || value.ToString().Length == 0)
            {
                return null;
            }

            //如果convertsionType为nullable类,声明一个NullableConverter类,该类提供从Nullable类到基础基元类型的转换
            NullableConverter nullableConverter = new NullableConverter(convertsionType);
            //将convertsionType转换为nullable对的基础基元类型
            convertsionType = nullableConverter.UnderlyingType;
        }
        return Convert.ChangeType(value, convertsionType);
    }
}

OK,现在该方法可以适用于值对任何类型的转换了,试试吧!

[.NET]將DataTable轉成List物件
Convert DataTable to List<T>

Convert to a Type on the fly in C#.NET
C#利用反射给对象赋值
如果该属性类型是未知非泛型类型,例如 int?
property.SetValue(obj,Convert.ChangeType(value, property.PropertyType), null);//类型转换。这时简单调用 ChangeType()方法,类型会报错。

2018年9月13日 星期四

[學習][RDLC] 報表頁數 依照群組分頁 Reset Page Number in RDLC Report by group


It can be done actually, but not without adding some custom code to the report:
Shared reportGroup as String
Shared newPage  as Integer

Public Function ResetPageNumber(newGroup as String)
  If Not (reportGroup = newGroup)
    reportGroup = newGroup 
    newPage  = 1
  Else
    newPage  = newPage  + 1
  End If
  Return newPage
End Function
Then in the footer, add text box for page number and make it's value:
= Code.ResetPageNumber(ReportItems!TextBoxWithYourGroupNameOrID.Value)

參考:
https://stackoverflow.com/questions/23300494/reset-page-number-in-rdlc-report-by-group
https://www.codeproject.com/Questions/1195280/Resetting-page-number-if-group-changes-in-RDLC-rep

注意:
頁尾一次只能參考一個欄位,如需多欄位的話,可以在最內的群組做組合即可。
或者資料群已做好排序,只要按最內的群組做分頁也可以,因為會重新RESET。

2017年12月4日 星期一

【除錯】Double 資料行的預設值無法使用,而消費者尚未設定新 Double 值。


問題:
1.提供者無法決定 Double 值。例如,剛建立資料列,Double 資料行的預設值無法使用,而消費者尚未設定新 Double 值。

2.提供者無法決定 Int16 值。例如,剛建立資料列,Int16 資料行的預設值無法使用,而消費者尚未設定新 Int16 值

解決:
當你看到類似的句子時,沒有錯不要懷疑,就是你的SQL要修改。

1.造成此次問題的原因為ACCESS中,SQL將數值除以零時所導致。SQL在ACCESS可正常執行,但除以零的欄位會顯示【錯誤】,而在程式介面CRUD撈完資料要塞入DataTable時,此時便會產生如問題所述之警告文字,因而程式中斷。

只要將SQL語法判斷零的字數,並依自己的程式需求改為正確的語法即可。
例如:將會導致錯誤的零改為正一或負一即可。

2.double 轉 int 精準度問題,CInt會直接報錯誤

2015年6月10日 星期三

[除錯] DataGridView RowValidating事件, 當按Escape取消時, 不要引發該事件...

as title...

參考:
Escaping DataGridView Row creation fires RowValidating. How to avoid this?

1)
private void dataGridView1_KeyDown(object sender, KeyEventArgs e) 
     if (e.KeyCode == Keys.Escape) 
          this.dataGridView1.RowValidating -= 
               new System.Windows.Forms.DataGridViewCellCancelEventHandler(this.dataGridView1_RowValidating); 

     this.dataGridView1.RowValidating += 
          new System.Windows.Forms.DataGridViewCellCancelEventHandler(this.dataGridView1_RowValidating); 
}


2)
if (!view.IsCurrentRowDirty ) return;